Convert LiveData to MutableLiveData

20,456

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 MutableLiveDatasince the setValue and postValue methods are public. Where as for LiveData they are protected which gives more control.

Share:
20,456
kike
Author by

kike

Contact here: https://kikebodi.com/contact

Updated on December 21, 2021

Comments

  • kike
    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 call getValue() instead postValue() and wouldn't work.

    Did anyone find a solution for this?