web-dev-qa-db-ja.com

ルーム-データベースの更新時にLiveDataオブザーバーがトリガーされない

以下のコードで調べようとしています。なぜ、データベースに新しいデータを入力しても、RoomのLiveDataオブザーバブルが新しいシフトを提供しないのはなぜですか。

これは私のアクティビティのonCreateメソッドに配置されます。

shiftsViewModel = ViewModelProviders.of(this).get(ShiftsViewModel.class);
shiftsViewModel
            .getShifts()
            .observe(this, this::populateAdapter);

これは、populateAdapterメソッドです。

private void populateAdapter(@NonNull final List<Shift> shifts){

    recyclerView.setAdapter(new SimpleItemRecyclerViewAdapter(shifts));
}

データベースにデータを取り込む次のコードもあります(Roomはメインスレッドの外部でコードを呼び出す必要があるため、RxJavaを使用してIOスレッドで作業を行います)。

@Override
public Observable<List<Shift>> persistShifts(@NonNull final List<Shift> shifts){

    return Observable.fromCallable(() -> {

        appDatabase.getShiftDao().insertAll(shifts);
        return shifts;
    })
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread());
}

ShiftsViewModelの監視を開始した後にpersistShiftsを呼び出すと、問題が発生します。私のオブザーバー(LiveData)が新しく追加されたすべてのシフトでトリガーされることを期待します。オブザーバーがトリガーされたことがわかりますが、代わりにシフトの空のリストが返されます。これを「機能させる」唯一の方法は、アクティビティを終了して(したがって、現在のViewModelを破棄して)再度入力することです。今回は、viewModelのLiveDataにより、予想どおり、以前に保持されていたすべてのシフトが得られます。

残りのコードは次のとおりです。

@Entity
public class Shift{

   @PrimaryKey
   private long id;

   private String start;
   private String end;
   private String startLatitude;
   private String startLongitude;
   private String endLatitude;
   private String endLongitude;
   private String image;
   ...

DAO:

@Dao
public interface ShiftDAO {

   @Query("SELECT * FROM shift")
   LiveData<List<Shift>> getAll();

   @Query("SELECT * FROM shift WHERE id = :id")
   LiveData<Shift> getShiftById(long id);

   @Insert(onConflict = OnConflictStrategy.REPLACE)
   void insertAll(List<Shift> shifts);
}

ViewModel:

public class ShiftsViewModel extends AndroidViewModel{

   private final ISQLDatabase sqlDatabase;

   private MutableLiveData<Shift> currentShift;
   private LiveData<List<Shift>> shifts;
   private boolean firstTimeCreated;


   public ShiftsViewModel(final Application application){

      super(application);

      this.sqlDatabase = ((ThisApplication) application).getSQLDatabase();
      this.firstTimeCreated = true;
   }

   public MutableLiveData<Shift> getCurrentlySelectedShift(){

      if(currentShift == null){
         currentShift = new MutableLiveData<>();
      }

      return currentShift;
   }

   public LiveData<List<Shift>> getShifts() {

      if(shifts == null){
         shifts = sqlDatabase.queryAllShifts();
      }

     return shifts;
   }

   public void setCurrentlySelectedShift(final Shift shift){

      currentShift = getCurrentlySelectedShift();

      currentShift.setValue(shift);
   }

   public boolean isFirstTimeCreated(){
      return firstTimeCreated;
   }

   public void alreadyUsed(){
      firstTimeCreated = false;
   }
}

なぜ、observe()コールバックで保持するシフトのリストをすぐに取得できないのですか?

20
Tiago

データを更新/挿入するためのDaoのインスタンスと、監視用のLiveDataを提供する別のインスタンスがあるため、Dagger 2を使用して同様の問題が発生しました。 Daoのシングルトンインスタンスを管理するようにDaggerを構成したら、ActivityでLiveDataを監視しながら、バックグラウンド(サービスの場合)にデータを挿入でき、onChange()コールバックが呼び出されます。

Daoのインスタンスは、データを挿入/更新し、観測用のLiveDataを提供するインスタンスと同じでなければなりません。

42
mukwux

私の場合、MediatorLiveDataを使用してデータベースから返されたエンティティを変換していて、変換された結果でsetValue()を呼び出すのを忘れていたため、メディエーターはデータベースへのリクエストのみに依存していて、結果を通知していませんでした。

override fun getItems() = MediatorLiveData<List<Item>>().apply {
    addSource(itemDao().getItems()) {
        // I was previously only converting the items, without calling 'value ='
        value = it.map(ItemWithTags::toDto)
    }
}
0
guy.gc