【问题标题】:Room - LiveData observer does not trigger when database is updatedRoom - LiveData 观察者在数据库更新时不会触发
【发布时间】:2017-06-25 01:41:39
【问题描述】:

我试图在下面的代码中找出,为什么在我用新数据填充数据库后,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() 回调中坚持的班次列表?

【问题讨论】:

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


    【解决方案1】:

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

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

    【讨论】:

    • 是的,要获得实时更新,您必须确保 Dao 的实例在所有操作中必须相同。
    • 我遇到了同样的问题,感谢您的回答,我发现我在RoomDatabase 提供方法上忘记了@Singleton。我想补充一点,就我而言,我有 2 个不同的 Daos 查询同一个表,其中一个与经典实体相关,一个与具有 2 个嵌入式实体的包装类相关,以重现连接查询。尽管对象不同,但LiveData 已正确更新,因此可能是RoomDatabase 必须是单例的。
    • 有类似的问题。通过将数据库保持为单例(而不是 DAO)来解决
    • 同样的问题,但我的问题是因为我在应用程序的单独进程/服务中进行插入/更新。一旦我回到主应用程序进程,它就开始工作了。
    • 没错,如果你使用 Dagger 来拥有你的 Db 或任何 DataManager 的实例,你必须在你的 AppProvider 中将你的 db 实例提供方法注释为@Singleton,这解决了我的问题。跨度>
    【解决方案2】:

    在我的例子中,这是因为我使用 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)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-11
      • 1970-01-01
      • 2021-04-08
      • 2018-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多