# #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. Я пробовал это несколько раз , но это все равно не работает