[英]android -MutableLiveData doesn't observe on new data
我正在使用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再次獲取數據。
當我調試時,它獲取數據但它沒有通知我的活動,我的意思是觀察者沒有在我的活動中被觸發。
我怎樣才能解決這個問題 ? 我的代碼出了什么問題?
在LiveData
和RxJava
使用中,你已經犯了幾個不同的重要錯誤,以及MVVM設計本身。
LiveData和RxJava
請注意, LiveData
和RxJava
是流。 它們不是一次性使用,因此您需要觀察相同的LiveData
對象,更重要的是,需要更新相同的LiveData
對象。
如果你看一下getCatsOnline()
方法,每次調用該方法時,它都會創建一個全新的LiveData
實例。 該實例與之前的LiveData
對象不同,因此無論是否正在偵聽前一個LiveData
對象,都不會通知新的更改。
還有一些額外的提示:
在getCatsOnline()
您正在訂閱另一個訂閱者內部的Observable
。 這是將RxJava
視為回叫的初學者的常見錯誤。 這不是回叫,你需要鏈接這些電話。
不要在模型層中subscribe
,因為它會中斷流,您無法確定何時取消訂閱。
使用AndroidSchedulers.mainThread()
是沒有意義的。 不需要在Model層中切換到主線程,特別是因為LiveData
觀察者只在主線程上運行。
不要將MutableLiveData
暴露給其他層。 只需返回LiveData
。
我要指出的最后一件事是你一起使用RxJava
和LiveData
。 既然你是兩者都是新手,我建議你堅持使用其中一個。 如果您必須同時使用兩者,請使用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())
)
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.