Reputation: 33
I have a usecase:
Expected: app load data
Actual: app display error that meaning state error cached, liveData is not emit
Repository class
class CategoryRepository(
private val api: ApiService,
private val dao: CategoryDao
) {
val categories: LiveData<Resource<List<Category>>> = liveData {
emit(Resource.loading(null))
try {
val data = api.getCategories().result
dao.insert(data)
emit(Resource.success(data))
} catch (e: Exception) {
val data = dao.getCategories().value
if (!data.isNullOrEmpty()) {
emit(Resource.success(data))
} else {
val ex = handleException(e)
emit(Resource.error(ex, null))
}
}
}
}
ViewModel class
class CategoryListViewModel(
private val repository: CategoryRepository
): ViewModel() {
val categories = repository.categories
}
Fragment class where LiveDate obsever
viewModel.apply {
categories.observe(viewLifecycleOwner, Observer {
// live data only trigger first time, when exit app then open again, live data not trigger
})
}
can you help me explain why live data not trigger in this usecase and how to fix? Thankyou so much
Update
I have resolved the above problem by replace val categories
by func categories()
at repository class. However, I don't understand and can't explain why it works properly with func
but not val
.
Upvotes: 0
Views: 410
Reputation: 8371
Why does this happen? This happens because your ViewModel
has not been killed yet. The ViewModel
on cleared()
is called when the Fragment
is destroyed. In your case your app is not killed and LiveData
would just emit the latest event already set. I don't think this is a case to use liveData
builder. Just execute the method in the ViewModel
when your Fragment gets in onResume()
:
override fun onResume(){
viewModel.checkData()
super.onResume()
}
// in the viewmodel
fun checkData(){
_yourMutableLiveData.value = Resource.loading(null)
try {
val data = repository.getCategories()
repository.insert(data)
_yourMutableLiveData.value = Resource.success(data)
} catch (e: Exception) {
val data = repository.getCategories()
if (!data.isNullOrEmpty()) {
_yourMutableLiveData.value = Resource.success(data)
} else {
val ex = handleException(e)
_yourMutableLiveData.value = Resource.error(ex,null)
}
}
}
Not sure if that would work, but you can try to add the listener directly in onResume()
but careful with the instantiation of the ViewModel
.
Small advice, if you don't need a value like in Resource.loading(null)
just use a sealed class
with object
UPDATE
Regarding your question that you ask why it works with a function and not with a variable, if you call that method in onResume
it will get executed again. That's the difference. Check the Fragment
or Activity
lifecycle before jumping to the ViewModel
stuff.
Upvotes: 1