Я выхватил вилку Василия из вашей вилки и провел некоторую фактическую отладку, чтобы посмотреть, что произойдет.
Может быть связано с тем, как ComputableLiveData выгружает вычисления onActive () в Executor.
Закрыть. Способ, которым LiveData<List<T>>
предоставляет доступ к Room, заключается в том, что он создает ComputableLiveData
, который отслеживает, был ли ваш набор данных признан недействительным ниже в Room.
trashedNotesLiveData = NoteplusRoomDatabase.instance().noteDao().getTrashedNotes();
Таким образом, когда в таблицу note
записывается, тогда InvalidationTracker, связанный с LiveData, будет вызывать invalidate()
, когда произойдет запись.
@Override
public LiveData<List<Note>> getNotes() {
final String _sql = "SELECT * FROM note where trashed = 0";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
return new ComputableLiveData<List<Note>>() {
private Observer _observer;
@Override
protected List<Note> compute() {
if (_observer == null) {
_observer = new Observer("note") {
@Override
public void onInvalidated(@NonNull Set<String> tables) {
invalidate();
}
};
__db.getInvalidationTracker().addWeakObserver(_observer);
}
Теперь нам нужно знать, что ComputableLiveData
invalidate()
будет на самом деле обновлять набор данных, если LiveData active .
// invalidation check always happens on the main thread
@VisibleForTesting
final Runnable mInvalidationRunnable = new Runnable() {
@MainThread
@Override
public void run() {
boolean isActive = mLiveData.hasActiveObservers();
if (mInvalid.compareAndSet(false, true)) {
if (isActive) { // <-- this check here is what's causing you headaches
mExecutor.execute(mRefreshRunnable);
}
}
}
};
Где liveData.hasActiveObservers()
:
public boolean hasActiveObservers() {
return mActiveCount > 0;
}
Таким образом, refreshRunnable
фактически выполняется только при наличии активного наблюдателя (afaik означает, что жизненный цикл по крайней мере запущен и наблюдает за текущими данными).
Это означает, что когда вы подписываетесь в TrashFragment, то происходит то, что ваши LiveData сохраняются в Activity, поэтому они сохраняются даже после удаления TrashFragment и сохраняют предыдущее значение.
Однако, когда вы открываете TrashFragment, затем TrashFragment подписывается, LiveData становится активным, ComputableLiveData проверяет наличие недействительности (что является истинным, поскольку никогда не пересчитывалось, потому что живые данные не были активными), вычисляет их асинхронно в фоновом потоке и после завершения значение публикуется.
Таким образом, вы получаете два обратных вызова, потому что:
1.) Первый вызов onChanged - это ранее сохраненное значение LiveData, сохраненное в ViewModel действия.
2.) Второй вызов onChanged - это недавно оцененный набор результатов из вашей базы данных, где вычисления были вызваны активацией активных данных из Room.
Так что технически это сделано намеренно. Если вы хотите убедиться, что вы получаете только «новейшее и наибольшее» значение, вам следует использовать ViewModel с фрагментами.
Возможно, вы также захотите начать наблюдения в onCreateView()
и использовать viewLifecycle
для жизненного цикла ваших LiveData (это новое дополнение, поэтому вам не нужно удалять наблюдателей в onDestroyView()
.
Если важно, чтобы Фрагмент видел последнее значение, даже если Фрагмент НЕ активен и НЕ наблюдает за ним, тогда, поскольку ViewModel имеет область действия, вы, возможно, захотите зарегистрировать наблюдателя в действии, чтобы убедиться, что в ваших LiveData есть активный наблюдатель.