将 LiveData 转换为 MutableLiveData
Convert LiveData to MutableLiveData
显然,Room 无法处理 MutableLiveData,我们必须坚持使用 LiveData,因为它 returns 出现以下错误:
error: Not sure how to convert a Cursor to this method's return type
我以这种方式在我的数据库助手中创建了一个 "custom" MutableLiveData:
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()
}
}
}
这样,我从数据库获取更新并可以保存 Profile
对象,但我不能修改属性。
例如:
mutableLiveData.value = Profile()
可以。
mutableLiveData.value.userName = "name"
会调用 getValue()
而不是 postValue()
并且不起作用。
有人找到解决方案了吗?
由于 Room 不支持 MutableLiveData
并且仅支持 LiveData
,因此您创建包装器的方法是我能想到的最佳方法。 Google
支持 MutableLiveData
会很复杂,因为 setValue
和 postValue
方法是 public
。至于 LiveData
,它们是 protected
,这提供了更多控制权。
叫我疯了,但 AFAIK 没有理由为您从 DAO 收到的对象使用 MutableLiveData。
想法是您可以通过 LiveData<List<T>>
公开一个对象
@Dao
public interface ProfileDao {
@Query("SELECT * FROM PROFILE")
LiveData<List<Profile>> getProfiles();
}
现在您可以观察它们了:
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;
});
所以如果你想制作这个实时数据"emit a new data and modify it",那么你需要将配置文件插入数据库。写入将重新评估此查询,一旦将新的配置文件值写入数据库,它将被发出。
dao.insert(profile); // this will make LiveData emit again
所以没有理由使用getValue
/setValue
,直接写入你的数据库即可。
在您的存储库中,您可以获得 LiveData
并将其转换为 MutableLivedata
:
var data= dao.getAsLiveData()
return MutableLiveData<T>(data.value)
如果你真的需要,那么你可以使用中介技巧。
在您的 ViewModel 中
val sourceProduct: LiveData<Product>() = repository.productFromDao()
val product = MutableLiveData<Product>()
val mediator = MediatorLiveData<Unit>()
init {
mediator.addSource(sourceProduct, { product.value = it })
}
在fragment/activity
observe(mediator, {})
observe(product, { /* handle product */ })
将 LiveData
转换为 MutableLiveData
的 Kotlin 扩展:
/**
* Transforms a [LiveData] into [MutableLiveData]
*
* @param T type
* @return [MutableLiveData] emitting the same values
*/
fun <T> LiveData<T>.toMutableLiveData(): MutableLiveData<T> {
val mediatorLiveData = MediatorLiveData<T>()
mediatorLiveData.addSource(this) {
mediatorLiveData.value = it
}
return mediatorLiveData
}
显然,Room 无法处理 MutableLiveData,我们必须坚持使用 LiveData,因为它 returns 出现以下错误:
error: Not sure how to convert a Cursor to this method's return type
我以这种方式在我的数据库助手中创建了一个 "custom" MutableLiveData:
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()
}
}
}
这样,我从数据库获取更新并可以保存 Profile
对象,但我不能修改属性。
例如:
mutableLiveData.value = Profile()
可以。
mutableLiveData.value.userName = "name"
会调用 getValue()
而不是 postValue()
并且不起作用。
有人找到解决方案了吗?
由于 Room 不支持 MutableLiveData
并且仅支持 LiveData
,因此您创建包装器的方法是我能想到的最佳方法。 Google
支持 MutableLiveData
会很复杂,因为 setValue
和 postValue
方法是 public
。至于 LiveData
,它们是 protected
,这提供了更多控制权。
叫我疯了,但 AFAIK 没有理由为您从 DAO 收到的对象使用 MutableLiveData。
想法是您可以通过 LiveData<List<T>>
@Dao
public interface ProfileDao {
@Query("SELECT * FROM PROFILE")
LiveData<List<Profile>> getProfiles();
}
现在您可以观察它们了:
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;
});
所以如果你想制作这个实时数据"emit a new data and modify it",那么你需要将配置文件插入数据库。写入将重新评估此查询,一旦将新的配置文件值写入数据库,它将被发出。
dao.insert(profile); // this will make LiveData emit again
所以没有理由使用getValue
/setValue
,直接写入你的数据库即可。
在您的存储库中,您可以获得 LiveData
并将其转换为 MutableLivedata
:
var data= dao.getAsLiveData()
return MutableLiveData<T>(data.value)
如果你真的需要,那么你可以使用中介技巧。
在您的 ViewModel 中
val sourceProduct: LiveData<Product>() = repository.productFromDao()
val product = MutableLiveData<Product>()
val mediator = MediatorLiveData<Unit>()
init {
mediator.addSource(sourceProduct, { product.value = it })
}
在fragment/activity
observe(mediator, {})
observe(product, { /* handle product */ })
将 LiveData
转换为 MutableLiveData
的 Kotlin 扩展:
/**
* Transforms a [LiveData] into [MutableLiveData]
*
* @param T type
* @return [MutableLiveData] emitting the same values
*/
fun <T> LiveData<T>.toMutableLiveData(): MutableLiveData<T> {
val mediatorLiveData = MediatorLiveData<T>()
mediatorLiveData.addSource(this) {
mediatorLiveData.value = it
}
return mediatorLiveData
}