问题
Apparently, Room is not able to handle MutableLiveData and we have to stick to LiveData as it returns the following error:
error: Not sure how to convert a Cursor to this method's return type
I created a "custom" MutableLiveData in my DB helper this way:
class ProfileRepository @Inject internal constructor(private val profileDao: ProfileDao): ProfileRepo{
override fun insertProfile(profile: Profile){
profileDao.insertProfile(profile)
}
val mutableLiveData by lazy { MutableProfileLiveData() }
override fun loadMutableProfileLiveData(): MutableLiveData<Profile> = mutableLiveData
inner class MutableProfileLiveData: MutableLiveData<Profile>(){
override fun postValue(value: Profile?) {
value?.let { insertProfile(it) }
super.postValue(value)
}
override fun setValue(value: Profile?) {
value?.let { insertProfile(it) }
super.setValue(value)
}
override fun getValue(): Profile? {
return profileDao.loadProfileLiveData().getValue()
}
}
}
This way, I get the updates from DB and can save the Profile
object but I cannot modify attributes.
For example:
mutableLiveData.value = Profile()
would work.
mutableLiveData.value.userName = "name"
would call getValue()
instead postValue()
and wouldn't work.
Did anyone find a solution for this?
回答1:
Call me crazy but AFAIK there is zero reason to use a MutableLiveData for the object that you received from the DAO.
The idea is that you can expose an object via LiveData<List<T>>
@Dao
public interface ProfileDao {
@Query("SELECT * FROM PROFILE")
LiveData<List<Profile>> getProfiles();
}
Now you can observe them:
profilesLiveData.observe(this, (profiles) -> {
if(profiles == null) return;
// you now have access to profiles, can even save them to the side and stuff
this.profiles = profiles;
});
So if you want to make this live data "emit a new data and modify it", then you need to insert the profile into the database. The write will re-evaluate this query and it will be emitted once the new profile value is written to db.
dao.insert(profile); // this will make LiveData emit again
So there is no reason to use getValue
/setValue
, just write to your db.
回答2:
If you really need to, then you can use the mediator trick.
In your ViewModel
val sourceProduct: LiveData<Product>() = repository.productFromDao()
val product = MutableLiveData<Product>()
val mediator = MediatorLiveData<Unit>()
init {
mediator.addSource(sourceProduct, { product.value = it })
}
In fragment/activity
observe(mediator, {})
observe(product, { //handle product })
回答3:
Since Room doesn't support MutableLiveData
and has support for LiveData
only, your approach of creating a wrapper is the best approach I can think of. It will be complicated for Google
to support MutableLiveData
since the setValue
and postValue
methods are public
. Where as for LiveData
they are protected
which gives more control.
回答4:
In your repository you can get LiveData
and transform it to MutableLivedata
:
var data= dao.getAsLiveData()
return MutableLiveData<T>(data.value)
来源:https://stackoverflow.com/questions/50943919/convert-livedata-to-mutablelivedata