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

查看:624
本文介绍了Room:Dao的LiveData每次更新都会触发Observer.onChanged,即使LiveData值没有变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆