web-dev-qa-db-ja.com

新しく接続されたオブザーバーに対してLiveDataオブザーバーが2回トリガーされる理由

LiveDataについての私の理解は、データの一連の履歴状態変化ではなく、データの現在の状態変化でオブザーバーをトリガーするということです。

現在、MainFragment書き込み操作を実行するRoomを使用して、non-trashed datatrashed dataに変更しています。

trashed dataを監視する別のTrashFragmentも使用します。

次のシナリオを検討してください。

  1. 現在0 ゴミ箱のデータがあります。
  2. MainFragmentは現在アクティブなフラグメントです。 TrashFragmentはまだ作成されていません。
  3. MainFragmentが追加されました1 ゴミ箱に入れられたデータ
  4. 現在、1個ありますゴミ箱のデータ
  5. ナビゲーションドロワーを使用して、MainFragmentTrashFragmentに置き換えます。
  6. TrashFragmentのオブザーバーは最初にonChangedを0とともに受け取りますゴミ箱に入れられたデータ
  7. 再び、TrashFragmentのオブザーバーは、2番目にonChangedを受け取り、1 trashed data

私の期待から外れているのは、項目(6)が起こらないことです。 TrashFragmentは最新のtrashed dataのみを受信する必要があります。これは1です。

これが私のコードです


TrashFragment.Java

public class TrashFragment extends Fragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        noteViewModel = ViewModelProviders.of(getActivity()).get(NoteViewModel.class);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ...

        noteViewModel.getTrashedNotesLiveData().removeObservers(this);
        noteViewModel.getTrashedNotesLiveData().observe(this, notesObserver);

MainFragment.Java

public class MainFragment extends Fragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        noteViewModel = ViewModelProviders.of(getActivity()).get(NoteViewModel.class);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ...

        noteViewModel.getNotesLiveData().removeObservers(this);
        noteViewModel.getNotesLiveData().observe(this, notesObserver);

NoteViewModel .Java

public class NoteViewModel extends ViewModel {
    private final LiveData<List<Note>> notesLiveData;
    private final LiveData<List<Note>> trashedNotesLiveData;

    public LiveData<List<Note>> getNotesLiveData() {
        return notesLiveData;
    }

    public LiveData<List<Note>> getTrashedNotesLiveData() {
        return trashedNotesLiveData;
    }

    public NoteViewModel() {
        notesLiveData = NoteplusRoomDatabase.instance().noteDao().getNotes();
        trashedNotesLiveData = NoteplusRoomDatabase.instance().noteDao().getTrashedNotes();
    }
}

部屋を扱うコード

public enum NoteRepository {
    INSTANCE;

    public LiveData<List<Note>> getTrashedNotes() {
        NoteDao noteDao = NoteplusRoomDatabase.instance().noteDao();
        return noteDao.getTrashedNotes();
    }

    public LiveData<List<Note>> getNotes() {
        NoteDao noteDao = NoteplusRoomDatabase.instance().noteDao();
        return noteDao.getNotes();
    }
}

@Dao
public abstract class NoteDao {
    @Transaction
    @Query("SELECT * FROM note where trashed = 0")
    public abstract LiveData<List<Note>> getNotes();

    @Transaction
    @Query("SELECT * FROM note where trashed = 1")
    public abstract LiveData<List<Note>> getTrashedNotes();

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    public abstract long insert(Note note);
}

@Database(
        entities = {Note.class},
        version = 1
)
public abstract class NoteplusRoomDatabase extends RoomDatabase {
    private volatile static NoteplusRoomDatabase INSTANCE;

    private static final String NAME = "noteplus";

    public abstract NoteDao noteDao();

    public static NoteplusRoomDatabase instance() {
        if (INSTANCE == null) {
            synchronized (NoteplusRoomDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(
                            NoteplusApplication.instance(),
                            NoteplusRoomDatabase.class,
                            NAME
                    ).build();
                }
            }
        }

        return INSTANCE;
    }
}

同じデータに対してonChangedが2回受信されないようにするにはどうすればよいですか?


デモ

この問題を示すためにデモプロジェクトを作成しました。

ご覧のとおり、MainFragmentで書き込み操作([ADD TRASHED NOTEボタンをクリック)]を実行した後、TrashFragmentに切り替えると、onChangedTrashFragmentが1回だけ呼び出されることを期待しています。ただし、2回呼び出されています。

enter image description here

デモプロジェクトは https://github.com/yccheok/live-data-problem からダウンロードできます。

49
Cheok Yan Cheng

PopUpでの複数のトリガーを回避するソリューションを探している場合、宛先フラグメントから元のフラグメントへのバックスタック

私の解決策は、フラグメントライフサイクルのonCreate()でLiveDataを観察することですライフサイクルの所有者をActivityとして、フラグメントライフサイクルのonDestroy()でオブザーバーを削除します

0
Muhamed Riyas M