使用带有参数(MVVM、存储库)的firestore查询更新android livedata

使用带有参数(MVVM、存储库)的firestore查询更新android livedata,android,mvvm,google-cloud-firestore,android-livedata,Android,Mvvm,Google Cloud Firestore,Android Livedata,我想用MVVM模型实现一个android应用程序。问题是我找不到一种方法来使用包含参数的Firestore调用更新ViewModel中的数据。repository类负责加载数据,这些数据要么从本地房间数据库(works)获取,要么从firestore获取 我的问题: 我的实现正确吗?从房间数据库获取数据是可行的。但是从Firestore加载数据不起作用。我认为问题在于,当FirestoreFoodWebservice类中的getFoods函数返回时,firestore查询尚未执行。我能做些什么来

我想用MVVM模型实现一个android应用程序。问题是我找不到一种方法来使用包含参数的Firestore调用更新ViewModel中的数据。repository类负责加载数据,这些数据要么从本地房间数据库(works)获取,要么从firestore获取

我的问题:

我的实现正确吗?从房间数据库获取数据是可行的。但是从Firestore加载数据不起作用。我认为问题在于,当FirestoreFoodWebservice类中的getFoods函数返回时,firestore查询尚未执行。我能做些什么来解决这个问题

我的架构如下所示:

MainActivity -> MainActivitiyViewModel -> FoodRepository -> 
(
    if (data is in room database) return from database
    else (get data from firestore webservice)
)
主要活动:

mainActivityViewModel = ViewModelProviders.of(this).get(MainActivityViewModel::class.java)
mainActivityViewModel.getFoodsFilteredByName().observe(this, Observer { foods ->
    run {
        searchResultAdapter.setData(foods)
        progressIndicator.visibility = View.INVISIBLE
    }
})
SearchResultAdapter:

fun setData(foods : List<Food>) {
    if (searchResult.isEmpty()) {
        searchResult = ArrayList(foods);
        notifyItemRangeInserted(0, searchResult.size)
        return
    }

    val result = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
        override fun getOldListSize(): Int {
            return searchResult.size
        }

        override fun getNewListSize(): Int {
            return foods.size
        }

        override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
            return searchResult[oldItemPosition].foodName === foods[newItemPosition].foodName
        }

        override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
            val newFood = foods[newItemPosition]
            val oldFood = searchResult[oldItemPosition]
            return newFood == oldFood
        }
    })
    searchResult = ArrayList(foods)
    result.dispatchUpdatesTo(this)
}
fun setData(食品:列表){
if(searchResult.isEmpty()){
searchResult=ArrayList(食品);
notifyItemRangeInserted(0,searchResult.size)
返回
}
val result=DiffUtil.calculateDiff(对象:DiffUtil.Callback(){
重写getOldListSize():Int{
返回searchResult.size
}
重写getNewListSize():Int{
返回食物。大小
}
覆盖乐趣项相同(oldItemPosition:Int,newItemPosition:Int):布尔值{
返回搜索结果[oldItemPosition]。foodName===foods[newItemPosition]。foodName
}
覆盖相同的内容(oldItemPosition:Int,newItemPosition:Int):布尔值{
val newFood=食品[newItemPosition]
val oldFood=搜索结果[oldItemPosition]
返回新食品==旧食品
}
})
searchResult=ArrayList(食品)
结果。dispatchUpdatesTo(此)
}
MainActivityViewModel:

private val foodsFilteredByName: LiveData<List<Food>>
private val filterName = MutableLiveData<String>()

init {
    val foodsDao = FoodRoomDatabase.getDatabase(application, viewModelScope).foodDao()
    val webservice = FirestoreFoodWebservice()
    repository = FoodRepository(foodsDao, webservice)
    foodsFilteredByName  = Transformations.switchMap(filterName) { c -> repository.getFoods(c) }
}

...

fun setFilter(name: String ) {
    filterName.value = name

}
private val foodsFilteredByName:LiveData
private val filterName=MutableLiveData()
初始化{
val foodsDao=FoodRoomDatabase.getDatabase(应用程序,viewModelScope).foodDao()
val webservice=FirestoreFoodWebservice()
repository=FoodRepository(foodsDao、webservice)
foodsFilteredByName=Transformations.switchMap(filterName){c->repository.getFoods(c)}
}
...
fun setFilter(名称:String){
filterName.value=名称
}
食品储备:

fun getFoods(foodName: String): MutableLiveData<List<Food>> {
    // if data exists in room database return the data
    // else:
    var foods: List<Food> = webservice.getFoods(foodName)
    val data = MutableLiveData<List<Food>>()
    data.value = foods

    return data
}
fun-getFoods(foodName:String):MutableLiveData{
//如果房间数据库中存在数据,则返回数据
//其他:
var foods:List=webservice.getFoods(foodName)
val data=MutableLiveData()
data.value=食品
返回数据
}
FirestoreFoodWebservice:

(在切换到MVVM之前,我在MainActivity中进行了查询。在那里查询工作正常。)

fun-getFoods(foodName:String):列表{
val query=//创建firestore查询
query.get().addOnSuccessListener{result->
用于(结果中的文档){
食品
//用结果中的数据填充食物
食物。添加(食物)
}
}.addOnFailureListener{/*ToDo:实现*/}
返回食物
//编辑:将foodNames更改为foods
}

正如您所建议的,问题在于
FirestoreFoodWebservice#getFoods
在firestore查询返回之前返回。您可以通过(1)使
getFoods
等待查询返回,(2)使
getFoods
使用回调返回查询结果,或(3)使
getFoods
返回
LiveData
实例来解决此问题。无法决定哪一个更好,因为您的代码中似乎有另一个关于
房间的问题。通常,您不应该能够同步地判断数据库中是否存在某些数据。请提供完整的
FoodRepository#getFoods
code.@SanlokLee谢谢。(3) 现在可以工作了。您是对的,从文件室同步加载数据不起作用。getFoods方法尚未完全实现。经过一些研究,我现在发现我的实现违反了“单一真相来源”原则。如果你把你的评论作为答案发表,我会把它标记为正确。当实现工作时,我会发布一个答案。问题是,正如您所建议的,
FirestoreFoodWebservice#getFoods
在firestore查询返回之前返回。您可以通过(1)使
getFoods
等待查询返回,(2)使
getFoods
使用回调返回查询结果,或(3)使
getFoods
返回
LiveData
实例来解决此问题。无法决定哪一个更好,因为您的代码中似乎有另一个关于
房间的问题。通常,您不应该能够同步地判断数据库中是否存在某些数据。请提供完整的
FoodRepository#getFoods
code.@SanlokLee谢谢。(3) 现在可以工作了。您是对的,从文件室同步加载数据不起作用。getFoods方法尚未完全实现。经过一些研究,我现在发现我的实现违反了“单一真相来源”原则。如果你把你的评论作为答案发表,我会把它标记为正确。我会在实现成功后发布一个答案。
fun getFoods(foodName: String): List<Food> {
    val query = // create firestore query

    query.get().addOnSuccessListener { result ->
        for (document in result) {
            var food = Food()
            // fill food with data from result
            foods.add(food)
        }
    }.addOnFailureListener { /*  ToDo: Implement */ }
    return foods
    // Edit: Changed foodNames to foods
}