Convert LiveData to MutableLiveData
Solution 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.
Solution 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 */ })
Solution 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.
Comments
-
kike over 2 years
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 callgetValue()
insteadpostValue()
and wouldn't work.Did anyone find a solution for this?