【问题标题】:android -MutableLiveData doesn't observe on new dataandroid -MutableLiveData 不观察新数据
【发布时间】:2019-05-01 07:41:17
【问题描述】:

我正在使用 mvvm 和 android 架构组件,我是这个架构的新手。

在我的应用程序中,我从 Web 服务中获取了一些数据并将它们显示在 recycleView 中,它工作正常。

然后我有一个添加新数据的按钮,当用户输入数据时,它会进入网络服务,然后我必须获取数据并再次更新我的适配器。

这是我的活动代码:

 private fun getUserCats() {
    vm.getCats().observe(this, Observer {
        if(it!=null) {
            rc_cats.visibility= View.VISIBLE
            pb.visibility=View.GONE
            catAdapter.reloadData(it)

        }
    })
}

这是视图模型:

class CategoryViewModel(private val model:CategoryModel): ViewModel() {

private lateinit var catsLiveData:MutableLiveData<MutableList<Cat>>

fun getCats():MutableLiveData<MutableList<Cat>>{
    if(!::catsLiveData.isInitialized){
        catsLiveData=model.getCats()
    }
    return catsLiveData;
}

fun addCat(catName:String){
    model.addCat(catName)
}

}

这是我的模型类:

class CategoryModel(
    private val netManager: NetManager,
    private val sharedPrefManager: SharedPrefManager) {

private lateinit var categoryDao: CategoryDao
private lateinit var dbConnection: DbConnection
private lateinit var lastUpdate: LastUpdate

fun getCats(): MutableLiveData<MutableList<Cat>> {
    dbConnection = DbConnection.getInstance(MyApp.INSTANCE)!!
    categoryDao = dbConnection.CategoryDao()
    lastUpdate = LastUpdate(MyApp.INSTANCE)

    if (netManager.isConnected!!) {
        return getCatsOnline();
    } else {
        return getCatsOffline();
    }
}

fun addCat(catName: String) {
    val Category = ApiConnection.client.create(Category::class.java)
    Category.newCategory(catName, sharedPrefManager.getUid())
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                    { success ->
                        getCatsOnline()
                    }, { error ->
                Log.v("this", "ErrorNewCat " + error.localizedMessage)
            }
            )
}

private fun getCatsOnline(): MutableLiveData<MutableList<Cat>> {
    Log.v("this", "online ");
    var list: MutableLiveData<MutableList<Cat>> = MutableLiveData()
    list = getCatsOffline()

    val getCats = ApiConnection.client.create(Category::class.java)
    getCats.getCats(sharedPrefManager.getUid(), lastUpdate.getLastCatDate())
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                    { success ->
                        list += success.cats
                        lastUpdate.setLastCatDate()

                        Observable.just(DbConnection)
                                .subscribeOn(Schedulers.io())
                                .subscribe({ db ->
                                    categoryDao.insert(success.cats)
                                })

                    }, { error ->
                Log.v("this", "ErrorGetCats " + error.localizedMessage);
            }
            )

    return list;
}

我从活动中调用 getCat,它进入模型并将其发送到我的网络服务,成功后我调用 getCatsOnline 方法再次从网络服务获取数据。

当我调试时,它获取数据但它没有通知我的活动,我的意思是观察者没有在我的活动中触发。

我该如何解决这个问题?我的代码有什么问题?

【问题讨论】:

    标签: android android-architecture-components android-livedata android-mvvm


    【解决方案1】:

    您在 LiveDataRxJava 的使用以及 MVVM 设计本身中犯了几个不同的重要错误。


    LiveData 和 RxJava

    请注意,LiveDataRxJava 是流。它们不是一次性使用的,因此您需要观察相同的LiveData 对象,更重要的是需要更新相同的LiveData 对象。

    如果您查看getCatsOnline() 方法,每次调用该方法时都会创建一个全新的LiveData 实例。该实例与之前的 LiveData 对象不同,因此任何正在侦听之前的 LiveData 对象的对象都不会收到新更改的通知。

    还有一些额外的提示:

    • getCatsOnline() 中,您正在订阅另一个订阅者内部的Observable。这是将RxJava 视为回调的初学者的常见错误。这不是回调,您需要链接这些调用。

    • 不要在 Model 层中subscribe,因为它会中断流并且您无法判断何时取消订阅。

    • 使用AndroidSchedulers.mainThread() 是没有意义的。无需切换到 Model 层的主线程,尤其是因为 LiveData 观察者只在主线程上运行。

    • 不要将MutableLiveData 暴露给其他层。只需返回 LiveData

    我要指出的最后一件事是您同时使用了RxJavaLiveData。由于您对两者都不熟悉,因此我建议您只使用其中之一。如果您必须同时使用两者,请使用LiveDataReactiveStreams 正确桥接这两者。


    设计

    如何解决这一切?我猜你想要做的是:

    (1) 视图需要分类 -> (2) 从服务器获取分类 -> (3) 使用新猫创建/更新可观察的list 对象,并将结果独立保存在数据库中 -> (4) list 实例应该自动通知活动。

    很难正确完成此操作,因为您拥有必须手动创建和更新的 list 实例。您还需要担心将此list 实例保留在何处以及保留多长时间。

    更好的设计应该是:

    (1) 视图需要类别 -> (2) 从 DB 获取 LiveData 并观察 -> (3) 从服务器获取新类别并使用服务器响应更新 DB -> (4) 视图自动通知因为它一直在观察 DB!

    这更容易实现,因为它具有这种单向依赖关系:View -> DB -> Server

    示例类别模型:

    class CategoryModel(
        private val netManager: NetManager,
        private val sharedPrefManager: SharedPrefManager) {
    
        private val categoryDao: CategoryDao
        private val dbConnection: DbConnection
        private var lastUpdate: LastUpdate // Maybe store this value in more persistent place..
    
    
        fun getInstance(netManager: NetManager, sharedPrefManager: SharedPrefManager) {
            // ... singleton
        }
    
    
        fun getCats(): Observable<List<Cat>> {
            return getCatsOffline();
        }
    
        // Notice this method returns just Completable. Any new data should be observed through `getCats()` method.
        fun refreshCats(): Completable {
            val getCats = ApiConnection.client.create(Category::class.java)
    
            // getCats method may return a Single
            return getCats.getCats(sharedPrefManager.getUid(), lastUpdate.getLastCatDate())
                .flatMap { success -> categoryDao.insert(success.cats) } // insert to db
                .doOnSuccess { lastUpdate.setLastCatDate() }
                .ignoreElement()
                .subscribeOn(Schedulers.io())
        }
    
    
        fun addCat(catName: String): Completable {
             val Category = ApiConnection.client.create(Category::class.java)
    
             // newCategory may return a Single
             return Category.newCategory(catName, sharedPrefManager.getUid())
                 .ignoreElement()
                 .andThen(refreshCats())
                 .subscribeOn(Schedulers.io())
            )
        }
    }
    

    我建议您阅读 Google 的 Guide to App Architecture 和其中一个 livedata-mvvm 示例 app

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-09-18
      • 1970-01-01
      • 1970-01-01
      • 2020-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多