MVVM架构下Repository从Firestore取数返回ViewModel时提前返回列表问题
问题根因
- ViewModel中先实例化了空
MutableLiveData并直接返回,viewModelScope.launch内的异步赋值逻辑执行时,方法已经将初始空LiveData返回给了Activity,Activity监听的是空对象,自然收不到后续数据更新。 - Repository层如果使用全局
_subCatalog成员变量存储数据,多次调用会互相覆盖,还容易引发内存泄漏。 - 额外注意:Repository查询条件的字段名写的是
mainCatalogtName,检查是否存在拼写错误(多了一个t),如果字段名不匹配也会导致查询结果为空。
代码修改方案
1. Repository层修改
每次调用创建独立的LiveData实例,避免全局变量干扰:
fun getSubCatalogs(mainCatalog: String): MutableLiveData<ArrayList<String>> { val subCatalog = MutableLiveData<ArrayList<String>>() subCatalogCollection.whereEqualTo("mainCatalogtName", mainCatalog) .addSnapshotListener { snapshot, e -> if (e != null) { subCatalog.postValue(arrayListOf()) return@addSnapshotListener } snapshot?.let { snap -> val catalogs = ArrayList<String>() snap.documents.forEach { doc -> doc.getString("subCatalogName")?.takeIf { it.isNotEmpty() }?.let { catalog -> catalogs.add(catalog) } } subCatalog.postValue(catalogs) } } return subCatalog }
2. ViewModel层修改
最简修改方式
直接返回Repository的LiveData即可:
fun getSubCatalogs(mainCatalog:String): MutableLiveData<ArrayList<String>> { return productDao.getSubCatalogs(mainCatalog) }
优化方案(避免多次添加Observer)
如果要避免每次选中主分类都新增Observer,可调整为ViewModel仅持有一个LiveData,Activity仅监听一次:
private val _subCatalogs = MutableLiveData<ArrayList<String>>() val subCatalogs: LiveData<ArrayList<String>> = _subCatalogs fun fetchSubCatalogs(mainCatalog: String) { productDao.getSubCatalogs(mainCatalog).observeForever { list -> _subCatalogs.postValue(list) } }
对应Activity代码调整为onCreate中仅监听一次:
// onCreate中执行一次绑定Observer addNamesViewModel.subCatalogs.observe(this@ActivityAddCatalogNames, { list -> val adapter = ArrayAdapter( this@ActivityAddCatalogNames, android.R.layout.simple_dropdown_item_1line, list ) binding?.subspinnercatalog?.adapter = adapter }) // 选中主分类时仅触发拉取数据 binding!!.mainspinnercatalog.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected( p0: AdapterView<*>?, p1: View?, position: Int, p3: Long ) { val mainCatalog = p0?.getItemAtPosition(position).toString() addNamesViewModel.fetchSubCatalogs(mainCatalog) } override fun onNothingSelected(p0: AdapterView<*>?) { } }
内容的提问来源于stack exchange,提问作者Sagar Deshmukh
相关产品推荐
相关产品推荐

