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

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

问题描述

我发现Dao返回的LiveData会在DB中更新行时调用它的观察者,即使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);

UI 中的某处

// 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 更新时仍会调用 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天全站免登陆