ListAdapter не обновляет RecyclerView данными из livedata

# #android #firebase #android-fragments #google-cloud-firestore #android-mvvm

Вопрос:

я использую firebase firestore с MVVM для загрузки данных, я использую слой репозитория для извлечения и хранения данных на уровне приложения, слой ViewModel для наблюдения за изменениями и выполнения вызовов репозитория, а также фрагмент для отображения данных. Проблема в том, что, хотя я могу успешно извлечь данные, они не отображаются в окне просмотра вторсырья.

Класс репозитория:

 fun fetchAppsFromFirestore() {

    val list = mutableListOf<AppModel>()

    firestore.collection(APPS_COLLECTION).get().addOnSuccessListener { querySnapshot ->

        for (doc in querySnapshot) {
            val app = doc.toObject(AppModel::class.java).also {
                it.docId = doc.id
            }
            list.add(app)
        }
        
        //This is a global mutableLiveData
        readingLiveData.value = list

    }
}
 

Класс ViewModel:

 fun getData() : LiveData<AppModelReadingResponse> {
    repo.fetchAppsFromFirestore()
    return repo.readingLiveData
}
 

До сих пор код делает то, что должен делать, если я войду в ViewModel, все элементы в списке будут там.

Класс адаптера:

 class FeaturedAppAdapter(val context: Context) :
ListAdapter<AppModel, FeaturedAppAdapter.FeaturedAppViewHolder>(AppModelComparator()) {

class AppModelComparator : DiffUtil.ItemCallback<AppModel>() {
    override fun areItemsTheSame(oldItem: AppModel, newItem: AppModel): Boolean {
        return oldItem.docId == newItem.docId
    }

    override fun areContentsTheSame(oldItem: AppModel, newItem: AppModel): Boolean {
        return oldItem == newItem
    }

}


inner class FeaturedAppViewHolder(private val binder: RowFeaturedAppsBinding) :
    RecyclerView.ViewHolder(binder.root) {

    fun bind(app: AppModel) {

        binder.rowFeaturedAppsTxtAppName.text = app.appName
        binder.rowFeaturedAppsTxtAppDescription.text = app.appDesc

    }
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FeaturedAppViewHolder {
    return FeaturedAppViewHolder(
        RowFeaturedAppsBinding.inflate(
            LayoutInflater.from(parent.context),
            parent,
            false
        )
    )
}

override fun onBindViewHolder(holder: FeaturedAppViewHolder, position: Int) {

    val app = getItem(position)
    holder.bind(app)

}
 

}

И на фрагменте, который я извлекаю данные:

 class HomeFragment : Fragment() {

companion object {
    private const val TAG = "tag_log_info"
}

//Layout components
private val binder by lazy {
    FragmentHomeBinding.inflate(layoutInflater)
}


//ViewModel
private val appsViewModel: AppsViewModel by viewModels {
    AppsViewModelFactory((requireActivity().application as MyApplication).appsRepository)
}

//RecyclerView
private lateinit var mAdapter: FeaturedAppAdapter

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View {

    
    setupRecyclerView()

    return binder.root
}

private fun setupRecyclerView() {

    mAdapter = FeaturedAppAdapter(requireContext())

    with(binder.fragmentHomeRecyclerView){
        this.adapter = mAdapter
        this.layoutManager = LinearLayoutManager(requireContext(),LinearLayoutManager.VERTICAL,false)
        this.setHasFixedSize(true)
    }

    observeData()
}

private fun observeData() {

    appsViewModel.getData().observe(viewLifecycleOwner) {
        Log.i(TAG, "observeData: $it") // This log shows that the data is here
        mAdapter.submitList(it)
    }

}
 

}

Итак, проблема в том , что, хотя журнал показывает, что у меня есть список данных по фрагменту, когда я звоню submitList(it) , ничего не происходит, и я не могу понять, почему. Что я здесь делаю не так?

Комментарии:

1. Я думаю, что вам может быть интересна эта статья, Как считывать данные из облачного магазина Firestore с помощью get()? . Существует четыре доступных подхода, в одном из которых используется LiveData. Попробуй и скажи мне, сработает ли это.

2. @AlexMamo спасибо за статью, очень полезную, но моя проблема не в получении данных, с помощью моего кода я успешно их получаю. Проблема в том, что я не могу обновить reyclerView с его помощью. Если я регистрирую или устанавливаю какое-либо текстовое представление с данными, оно работает нормально, но когда я использую его в RecyclerView, ничего не происходит, это настоящая проблема.

3. В этом случае попробуйте прослушать обновления в режиме реального времени .

Ответ №1:

В функции observeData, как только данные будут установлены в адаптер, вы должны вызвать notifyDataSetChanged функцию, чтобы сообщить адаптеру об изменении данных.

Таким образом, ваша функция наблюдателя становится

  private fun observeData() {
    appsViewModel.getData().observe(viewLifecycleOwner) {
      Log.i(TAG, "observeData: ${it.list}") // This log shows that the data is here
      mAdapter.submitList(it.list)
      mAdapter.notifyDataSetChanged()
   }
}
 

Дай мне знать, если это не сработает.

Комментарии:

1. Я пробовал это несколько раз , но это все равно не работает