Convert LiveData to MutableLiveData

生来就可爱ヽ(ⅴ<●) 提交于 2020-01-12 15:47:10

问题


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 MutableLiveDatasince 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!