簡體   English   中英

Room - LiveData 觀察者不會在數據庫更新時觸發

[英]Room - LiveData observer does not trigger when database is updated

我試圖在下面的代碼中找出為什么在我用新數據填充數據庫后 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());
}

當我開始觀察我的 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
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;
   }
}

為什么我沒有立即獲得我在 observe() 回調中堅持的班次列表?

我在使用 Dagger 2 時遇到了類似的問題,這是由 Dao 的不同實例引起的,一個用於更新/插入數據,另一個實例提供用於觀察的 LiveData。 一旦我將 Dagger 配置為管理 Dao 的單例實例,那么我就可以在后台插入數據(在我的情況下是在服務中),同時在我的 Activity 中觀察 LiveData - 並且將調用 onChange() 回調。

歸結為 Dao 的實例必須是插入/更新數據並提供 LiveData 以供觀察的同一個實例。

就我而言,這是因為我使用 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)
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM