Room:Dao的LiveData每次更新都会触发Observer.onChanged,即使LiveData值没有变化 [英] Room : LiveData from Dao will trigger Observer.onChanged on every Update, even if the LiveData value has no change
问题描述
我发现Dao返回的LiveData会在数据库中更新该行时立即调用其观察者,即使LiveData值显然没有改变.
I found that the LiveData returned by Dao will call its observer whenever the row is updated in DB, even if the LiveData value is obviously not changed.
考虑类似以下示例的情况:
Consider a situation like the following example :
示例实体
@Entity
public class User {
public long id;
public String name;
// example for other variables
public Date lastActiveDateTime;
}
道例
@Dao
public interface UserDao {
// I am only interested in the user name
@Query("SELECT name From User")
LiveData<List<String>> getAllNamesOfUser();
@Update(onConflict = OnConflictStrategy.REPLACE)
void updateUser(User user);
}
后台线程中的某个地方
Somewhere in background thread
UserDao userDao = //.... getting the dao
User user = // obtain from dao....
user.lastActiveDateTime = new Date(); // no change to user.name
userDao.updateUser(user);
用户界面中的某个地方
// omitted ViewModel for simplicity
userDao.getAllNamesOfUser().observe(this, new Observer<List<String>> {
@Override
public void onChanged(@Nullable List<String> userNames) {
// this will be called whenever the background thread called updateUser.
// If user.name is not changed, it will be called with userNames
// with the same value again and again when lastActiveDateTime changed.
}
});
在此示例中,ui只对用户名感兴趣,因此对LiveData的查询仅包括名称字段.但是,即使仅更新其他字段,仍然会在Dao Update上调用observer.onChanged. (实际上,如果我不对User实体进行任何更改,而是调用UserDao.updateUser,则仍将调用observer.onChanged)
In this example, the ui is only interested to user name so the query for LiveData only includes the name field. However the observer.onChanged will still be called on Dao Update even only other fields are updated. (In fact, if I do not make any change to User entity and call UserDao.updateUser, the observer.onChanged will still be called)
这是Dao LiveData在Room中的设计行为吗?我是否有可能解决此问题,以便仅在更新选定字段时调用观察者?
Is this the designed behaviour of Dao LiveData in Room? Is there any chance I can work around this, so that the observer will only be called when the selected field is updated?
我更改为使用以下查询来更新lastActiveDateTime值,如注释中的KuLdip PaTel所示.用户名LiveData的观察者仍然被调用.
Edit : I changed to use the following query to update the lastActiveDateTime value as KuLdip PaTel in comment suggest. The observer of LiveData of user name is still called.
@Query("UPDATE User set lastActiveDateTime = :lastActiveDateTime where id = :id")
void updateLastActiveDateTime(Date lastActiveDateTime, int id);
推荐答案
这种情况称为观察者的误报. 请检查链接中提到的第7点,以避免这样的问题.
This situation is known as false positive notification of observer. Please check point number 7 mentioned in the link to avoid such issue.
下面的示例是用kotlin编写的,但是您可以使用其Java版本来使其正常工作.
Below example is written in kotlin but you can use its java version to get it work.
fun <T> LiveData<T>.getDistinct(): LiveData<T> {
val distinctLiveData = MediatorLiveData<T>()
distinctLiveData.addSource(this, object : Observer<T> {
private var initialized = false
private var lastObj: T? = null
override fun onChanged(obj: T?) {
if (!initialized) {
initialized = true
lastObj = obj
distinctLiveData.postValue(lastObj)
} else if ((obj == null && lastObj != null)
|| obj != lastObj) {
lastObj = obj
distinctLiveData.postValue(lastObj)
}
}
})
return distinctLiveData
}
这篇关于Room:Dao的LiveData每次更新都会触发Observer.onChanged,即使LiveData值没有变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!