Room - LiveData观察者在数据库更新时不会触发

时间:2017-06-25 01:41:40

标签: android viewmodel android-room android-architecture-components android-livedata

我试图在下面的代码中找到,为什么一旦我用新数据填充数据库,Room的LiveData observable就不会给我新的转变。

这是我的活动的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));
}

我还有以下代码填充数据库(我使用RxJava在IO线程上完成工作,因为Room需要在主线程之外调用它的代码):

@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());
}

在我开始观察shiftViewModel之后调用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);
}

视图模型:

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;
   }
}

为什么我没有得到我在观察()回调中坚持的班次列表?

2 个答案:

答案 0 :(得分:34)

我使用Dagger 2遇到了类似的问题,这个问题是由Dao的不同实例引起的,一个用于更新/插入数据,另一个实例提供LiveData用于观察。一旦我配置Dagger来管理Dao的单例实例,那么我可以在后台插入数据(在我的情况下在服务中),同时在我的Activity中观察LiveData - 并且将调用onChange()回调。

归结为Dao的实例必须是插入/更新数据并提供LiveData以供观察的相同实例。

答案 1 :(得分:1)

在我的情况下,这是因为我正在使用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)
    }
}