Room : LiveData from Dao will trigger Observer.onChanged on every Update, even if the LiveData value has no change

前端 未结 5 1360
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-05 10:14

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 s

5条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-05 10:48

    Avoid false positive notifications for observable queries
    Let’s say that you want to get a user based on the user id in an observable query:

    @Query(“SELECT * FROM Users WHERE userId = :id)
    fun getUserById(id: String): LiveData
    

    You’ll get a new emission of the User object whenever that user updates. But you will also get the same object when other changes (deletes, updates or inserts) occur on the Users table that has nothing to do with the User you’re interested in, resulting in false-positive notifications. Even more, if your query involves multiple tables, you’ll get a new emission whenever something changed in any of them.

    If your query returns a LiveData, you can use a MediatorLiveData that only allows distinct object emissions from a source.

    fun  LiveData.getDistinct(): LiveData {
        val distinctLiveData = MediatorLiveData()
        distinctLiveData.addSource(this, object : Observer {
            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
    }
    

    In your DAOs, make method that returns the distinct LiveData public and the method that queries the database protected.

    @Dao
     abstract class UserDao : BaseDao() {
       @Query(“SELECT * FROM Users WHERE userid = :id”)
       protected abstract fun getUserById(id: String): LiveData
       fun getDistinctUserById(id: String): 
             LiveData = getUserById(id).getDistinct()
    }
    

    See more of the code here and also in Java.

提交回复
热议问题