android -MutableLiveData не наблюдает за новыми данными - PullRequest
0 голосов
/ 01 мая 2019

Я использую mvvm и компонент архитектуры Android, я новичок в этой архитектуре.

В моем приложении я получаю некоторые данные из веб-сервиса и показываю их в 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, чтобы снова получить данные из веб-службы.

когда я отлаживал, он получает данные, но не уведомляет мою активность, я имею в виду, что наблюдатель не запускается в моей деятельности.

как я могу это исправить? что не так с моим кодом?

1 Ответ

0 голосов
/ 01 мая 2019

Вы допустили несколько разных ошибок разной важности при использовании LiveData и RxJava, а также в самой конструкции MVVM.


LiveData и RxJava

Обратите внимание, что LiveData и RxJava являются потоками.Они не используются один раз, поэтому вам нужно наблюдать один и тот же объект LiveData, и что более важно, тот же самый объект LiveData должен обновляться.

Если вы посмотрите на метод getCatsOnline(), каждый разметод вызывается, он создает совершенно новый экземпляр LiveData.Этот экземпляр отличается от предыдущего объекта LiveData, поэтому все, кто прослушивает предыдущий объект LiveData, не получат уведомление о новом изменении.

И несколько дополнительных советов:

  • В getCatsOnline() вы подписываетесь на Observable внутри другого абонента.Это распространенная ошибка новичков, которые рассматривают RxJava как обратный звонок.Это не обратный вызов, и вам нужно связать эти вызовы.

  • Не subscribe в Model layer, потому что он прерывает поток и вы не можетесообщите, когда отписаться.

  • Нет смысла когда-либо использовать AndroidSchedulers.mainThread().Нет необходимости переключаться на основной поток в слое Model , тем более что LiveData наблюдатели работают только на основном потоке.

  • Не подвергать MutableLiveData другимслой.Просто верните как LiveData.

Последнее, на что я хочу обратить внимание, это то, что вы используете RxJava и LiveData вместе.Поскольку вы новичок в обоих, я рекомендую вам придерживаться только одного из них.Если вам необходимо использовать оба, используйте LiveDataReactiveStreams , чтобы правильно соединить эти два.


Дизайн

Как все это исправить?Я предполагаю, что вы пытаетесь сделать следующее:

(1) просмотреть категорию потребностей -> (2) получить категории с сервера -> (3) создать / обновить наблюдаемый объект list сновые кошки и независимо сохраняют результат в DB -> (4) list экземпляр должен автоматически уведомлять об активности.

Сложно справиться с этим правильно, потому что у вас есть этот list экземпляр, который у вас естьвручную создавать и обновлять.Вам также нужно позаботиться о том, где и как долго хранить этот экземпляр list.

Лучший дизайн будет выглядеть так:

(1) просмотр категории потребностей -> (2) получить LiveData из БД и наблюдать -> (3) получать новые категории с сервера и обновлять БД с помощью ответа сервера -> (4) представление уведомляется автоматически, потому что оно наблюдает за БД!

Это гораздо прощереализовать, потому что он имеет эту одностороннюю зависимость: View -> DB -> Server

Пример 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())
        )
    }
}

Я рекомендую прочитать Руководство по архитектуре приложения и один из этих примеров liveata-mvvm app от Google.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...