Room: Dao's LiveData launches Observer.onChanged for each update, even if the LiveData value is unchanged

I found that the LiveData returned by Dao will call its observer whenever the row is updated in the database, even if the LiveData value obviously does not change.

Consider a situation similar to the following example:

Entity Example

@Entity
public class User {
    public long id;
    public String name;
    // example for other variables
    public Date lastActiveDateTime;
}

Tao example

@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 the background thread

UserDao userDao = //.... getting the dao
User user = // obtain from dao....
user.lastActiveDateTime = new Date(); // no change to user.name
userDao.updateUser(user);

Somewhere in the interface

// 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.
    }
});

In this example, the user interface is only interested in the username, so the LiveData query includes only the name field. However, Observer.onChanged will still be called when updating Dao, even if only other fields are updated. (In fact, if I don't make any changes to the User entity and call UserDao.updateUser, Observer.onChanged will still be called)

Dao LiveData ? , , ?


: , lastActiveDateTime, KuLdip PaTel . LiveData - .

@Query("UPDATE User set lastActiveDateTime = :lastActiveDateTime where id = :id")
void updateLastActiveDateTime(Date lastActiveDateTime, int id);
+11
2

. , 7, .

kotlin, java, .

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
}
+4

.

:

1) :

private LiveData<List<WordsTableEntity>> listLiveData;
// listLiveData = ... //init our LiveData...
listLiveData.observe(this, new Observer<List<WordsTableEntity>>() {
        @Override
        public void onChanged(@Nullable List<WordsTableEntity> wordsTableEntities) {

        }
    });

, .

, LiveData. - onChanged , userDao.getAllNamesOfUser().observe(this, new Observer.

Observer LiveData.observe(...

@Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        observer = new Observer<List<WordsTableEntity>>() {
            @Override
            public void onChanged(@Nullable List<WordsTableEntity> wordsTableEntities) {
                adapter.setWordsTableEntities(wordsTableEntities);
                progressBar.setVisibility(View.GONE);
            }
        };
    }

LiveData.observe(observer LieData , , .

2)

public void callMethodMultipleTimes(String searchText) {
            listLiveData = App.getRepositoryRoomDB().searchDataExceptChapter(searchText);
            listLiveData.observe(this, observer);
    }

, , observer , callMethodMultipleTimes();

listLiveData , .

listLiveData = App.getRepositoryRoomDB().searchDataExceptChapter(searchText);

, listLiveData.removeObserver(observer);

listLiveData = App.getRepositoryRoomDB().searchDataExceptChapter(searchText);

1) - listLiveData.removeObserver(our anonimous Observer); .

, :

private Observer observer;
private LiveData<List<WordsTableEntity>> listLiveData;
@Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        observer = new Observer<List<WordsTableEntity>>() {
            @Override
            public void onChanged(@Nullable List<WordsTableEntity> wordsTableEntities) {
                adapter.setWordsTableEntities(wordsTableEntities);
                progressBar.setVisibility(View.GONE);
            }
        };
    }

public void searchText(String searchText) {
            if (listLiveData != null){
                listLiveData.removeObservers(this);
            }
            listLiveData = App.getRepositoryRoomDB().searchDataExceptChapter(searchText);
            listLiveData.observe(this, observer);
    }

. .

, - .

PS

    // Room components
    implementation "android.arch.persistence.room:runtime:1.1.1"
    annotationProcessor "android.arch.persistence.room:compiler:1.1.1"
    androidTestImplementation "android.arch.persistence.room:testing:1.1.1"

    // Lifecycle components
    implementation "android.arch.lifecycle:extensions:1.1.1"
    annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
0

Source: https://habr.com/ru/post/1689036/


All Articles