android -MutableLiveData没有观察到新数据

问题描述 投票:0回答:1

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

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

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

这是我的活动代码:

 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,它进入模型并将其发送到我的Web服务,成功后我调用getCatsOnline方法从webservice再次获取数据。

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

我怎样才能解决这个问题 ?我的代码出了什么问题?

android android-architecture-components android-livedata android-mvvm
1个回答
0
投票

LiveDataRxJava的使用中,你已经犯了几个不同重要的错误,以及MVVM设计本身。

LiveData和RxJava

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

如果你看一下getCatsOnline()方法,每次调用该方法时,它都会创建一个全新的LiveData实例。该实例与之前的LiveData对象不同,因此无论何时收听以前的LiveData对象都不会收到新的更改通知。

还有一些额外的提示:

  • getCatsOnline(),您订阅了另一个订阅者内部的Observable。这是将RxJava视为回叫的初学者的常见错误。这不是回叫,你需要链接这些电话。
  • 不要在模型层中使用subscribe,因为它会破坏流并且您无法确定何时取消订阅。
  • 使用AndroidSchedulers.mainThread()没有意义。没有必要在Model层中切换到主线程,特别是因为LiveData观察者只在主线程上运行。
  • 不要将MutableLiveData暴露给其他层。只需返回LiveData

我要指出的最后一件事是你一起使用RxJavaLiveData。既然你是两者都是新手,我建议你坚持使用其中一个。如果您必须同时使用两者,请使用LiveDataReactiveStreams正确桥接这两者。

设计

如何解决所有这些问题?我猜你要做的是:

(1)查看需求类别 - >(2)从服务器获取类别 - >(3)用新猫创建/更新可观察的list对象,并将结果独立保存在DB中 - >(4)list实例应通知活动自动。

很难正确地解决这个问题,因为你必须手动创建和更新这个list实例。你还需要担心保持这个list实例的位置和时间。

更好的设计是:

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

这更容易实现,因为它具有这种单向依赖性:视图 - >数据库 - >服务器

示例CategoryModel:

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())
        )
    }
}

我建议你阅读Guide to App Architecture和来自Google的其中一个来自谷歌的liveata-mvvm示例app

© www.soinside.com 2019 - 2024. All rights reserved.