You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 18:54:04