Firestore写入正常但无法读取数据且无报错问题求助
Firestore异步读取数据为空问题修复
问题现象
- Firestore数据写入功能正常运行
- 参考官方文档编写的读取代码全程无报错、不触发失败回调,但无法获取到任何数据
- 调用读取方法后立刻获取数据列表为空,RecyclerView无法展示内容
问题代码
Fragment 实现
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) init() } private fun init() { db = FirebaseFirestore.getInstance() mFirestoreRef = db.collection("users").document(USER_ID).collection("deals") val viewModel = ViewModelProvider(this).get(DealsViewModel::class.java) viewModel.retriveData(mFirestoreRef) recyclerView = binding.rcView adapter = TradeNoteAdapter() recyclerView.adapter = adapter var notes = viewModel.getAllNotes() adapter.setList(notes) }
ViewModel 实现
import android.widget.Toast import androidx.lifecycle.ViewModel import com.google.firebase.firestore.CollectionReference import space.timur.tradenotefirebase.APP import space.timur.tradenotefirebase.model.TradeNoteModel class DealsViewModel : ViewModel() { private var notes: ArrayList<TradeNoteModel> = ArrayList() fun retriveData(firestoreReference: CollectionReference){ firestoreReference.get() .addOnSuccessListener { documents -> for(document in documents){ var note = document.toObject(TradeNoteModel::class.java) notes.add(note) } }.addOnFailureListener{ e-> Toast.makeText(APP, e.message, Toast.LENGTH_SHORT).show() } } fun getAllNotes(): ArrayList<TradeNoteModel> { return notes } }
问题根因
Firestore的get()方法是异步网络请求,调用后不会阻塞当前线程等待结果返回。你在调用retriveData()后立刻执行getAllNotes()时,请求还在网络传输阶段,notes列表还没被写入数据,自然是空的。等后续addOnSuccessListener回调执行、往notes里添加数据时,你早就把空列表传给了适配器,也没有通知适配器数据更新,所以RecyclerView一直显示空白。
修复方案
使用LiveData持有加载完成的数据,让Fragment观察数据变化,数据拉取完成后自动刷新UI:
修正后的ViewModel
import android.widget.Toast import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import com.google.firebase.firestore.CollectionReference import space.timur.tradenotefirebase.APP import space.timur.tradenotefirebase.model.TradeNoteModel class DealsViewModel : ViewModel() { private val _notes = MutableLiveData<List<TradeNoteModel>>() val notes: LiveData<List<TradeNoteModel>> = _notes fun retriveData(firestoreReference: CollectionReference){ firestoreReference.get() .addOnSuccessListener { documents -> val noteList = arrayListOf<TradeNoteModel>() for(document in documents){ val note = document.toObject(TradeNoteModel::class.java) noteList.add(note) } // 数据加载完成后发送到LiveData _notes.postValue(noteList) }.addOnFailureListener{ e-> Toast.makeText(APP, e.message, Toast.LENGTH_SHORT).show() } } }
修正后的Fragment初始化逻辑
private fun init() { db = FirebaseFirestore.getInstance() mFirestoreRef = db.collection("users").document(USER_ID).collection("deals") val viewModel = ViewModelProvider(this).get(DealsViewModel::class.java) recyclerView = binding.rcView adapter = TradeNoteAdapter() recyclerView.adapter = adapter // 观察数据变化,数据加载完成后自动刷新列表 viewModel.notes.observe(viewLifecycleOwner) { noteList -> adapter.setList(noteList) } // 触发数据拉取 viewModel.retriveData(mFirestoreRef) }
注意:如果不使用LiveData,也可以直接在
addOnSuccessListener回调中拿到数据后更新适配器,但绝对不能在异步请求刚发起时同步读取结果,Firestore所有网络操作默认都是异步执行的,不会立刻返回结果。
内容的提问来源于stack exchange,提问作者Timson01
相关产品推荐
相关产品推荐

