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