Android LiveData和Room(getValue返回NULL)

学向勤中得,萤窗万卷书。这篇文章主要讲述Android LiveData和Room:getValue返回NULL相关的知识,希望能为你提供帮助。
使用ROOM从DB读取数据并返回LiveData时,getValue()方法返回null。我一直无法理解一会儿出了什么问题。你能帮忙解决这个问题吗?数据库中有数据,似乎更像是我如何使用LiveData对象。
活动:

public class ExercisesViewActivity extends AppCompatActivity implements View.OnClickListener {private ExerciseViewModel exerciseViewModel; private ExercisesAdapter recyclerViewerAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_exercises_view); Toolbar toolbar = findViewById(R.id.toolbar_exercise_view_activity); toolbar.setTitle("Exercises"); setSupportActionBar(toolbar); ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setDisplayShowHomeEnabled(true); }RecyclerView recyclerView = findViewById(R.id.exercise_view_recycle_viewer); RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext()); recyclerView.setLayoutManager(layoutManager); this.recyclerViewerAdapter = new ExercisesAdapter(); recyclerView.setAdapter(recyclerViewerAdapter); this.exerciseViewModel = ViewModelProviders.of(this).get(ExerciseViewModel.class); this.exerciseViewModel.setFilters("", ""); //this.exerciseViewModel.selectAll(); this.exerciseViewModel.select().observe(this, exercises -> { if (exercises != null) { this.recyclerViewerAdapter.updateDataset(exercises); } }); Button button = findViewById(R.id.test_button); button.setOnClickListener(this); }@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: onBackPressed(); break; }return true; }@Override public void onClick(View v) { this.exerciseViewModel.setFilters("", ""); //this.exerciseViewModel.select().observe(this, exercises -> { //if (exercises != null) { //this.recyclerViewerAdapter.updateDataset(exercises); //} //}); } }

视图模型:
public class ExerciseViewModel extends AndroidViewModel { ExercisesRepository repository; MutableLiveData< List< Exercise> > data; public ExerciseViewModel(Application application) { super(application); this.data = https://www.songbingjia.com/android/new MutableLiveData< > (); this.repository = new ExercisesRepository(application); }public void setFilters(String muscleGroups, String type) { LiveData< List< Exercise> > listLiveData = this.repository.filterSelect(muscleGroups, type); this.data.setValue(listLiveData.getValue()); }public void selectAll() { //this.data.setValue(this.repository.selectAll().getValue()); }public LiveData< List< Exercise> > select() { return data; }public void insert(Exercise exercise) { this.repository.insert(exercise); } }

【Android LiveData和Room(getValue返回NULL)】库:
public class ExercisesRepository { private ExerciseDao dao; public ExercisesRepository(Application context) { WorkoutRoomDatabase database = WorkoutRoomDatabase.getDb(context); this.dao = database.exerciseDao(); }public LiveData< List< Exercise> > filterSelect(String muscleGroups, String type) { return this.dao.filterSelect("%" + muscleGroups + "%", "%" + type + "%"); }public LiveData< List< Exercise> > selectAll() { return this.dao.selectAll(); }public void insert(Exercise exercise) { new insertAsyncTask(this.dao).execute(exercise); }private static class insertAsyncTask extends AsyncTask< Exercise, Void, Void> {private ExerciseDao exerciseDao; insertAsyncTask(ExerciseDaodao) { exerciseDao = dao; }@Override protected Void doInBackground(final Exercise... params) { exerciseDao.insert(params[0]); return null; } } }

DAO:
@Dao public interface ExerciseDao { @Query("SELECT * FROM exercises WHERE muscleGroups LIKE :muscleGroup AND type LIKE :type") LiveData< List< Exercise> > filterSelect(String muscleGroup, String type); @Query("SELECT * FROM exercises") LiveData< List< Exercise> > selectAll(); @Insert void insert(Exercise exercise); @Update void update(Exercise exercise); @Delete void delete(Exercise exercise); @Query("DELETE FROM exercises") void deleteAll(); }

更新:
如果在我的viewModel中我更改了filter函数以返回一个新的LiveData对象,则正在获取正确的数据:
public LiveData< List< Exercise> > filterSelect(String muscleGroups, String type) { return this.dao.filterSelect("%" + muscleGroups + "%", "%" + type + "%"); }

但是在我的Activity中我需要创建一个新的观察者,因为现在数据是由LiveData的新实例提供的:
@Override public void onClick(View v) { this.exerciseViewModel.setFilters("Biceps", "weight"); this.exerciseViewModel.select().observe(this, exercises -> { if (exercises != null) { this.recyclerViewerAdapter.updateDataset(exercises); } }); }

现在这是正确的方法:/
答案您应该查看MediatorLiveData而不是MutableLiveData,它将允许您从存储库中预测更改。
这将类似于下面,您将存储库数据作为数据源添加到mediatorLiveData。然后,当您从存储库接收数据时,它将触发回调,然后您可以通过调用setValue从mediatorLiveData发出数据。
public class ExerciseViewModel extends AndroidViewModel { ExercisesRepository repository; MediatorLiveData< List< Exercise> > mediatorLiveData = https://www.songbingjia.com/android/new MediatorLiveData< > (); public ExerciseViewModel(Application application) { super(application); this.repository = new ExercisesRepository(application); }public void setFilters(String muscleGroups, String type) { LiveData< List< Exercise> > repositoryLiveData = this.repository.filterSelect(muscleGroups, type); mediatorLiveData.addSource(repositoryLiveData, exercisList -> { mediatorLiveData.removeSource(repositoryLiveData); mediatorLiveData.setValue(exercisList); }); }public LiveData< List< Exercise> > select() { return mediatorLiveData; }

另一答案您试图在filterSelete中使用空值获取类似搜索。 this.exerciseViewModel.setFilters("", ""); 。这个过滤器基本上是一个问题。你不能像搜索一样做空。在此情况下,您可以使用loadAll查询。
@Query("SELECT * FROM exercises") LiveData< List< Exercise> > loadAll();
编辑:
public LiveData< List< Exercise> > filterSelect(String muscleGroups, String type) {if(muscleGroups == "" & & type == "") { return this.dao.loadAll()}else {return this.dao.filterSelect("%" + muscleGroups + "%", "%" + type + "%"); }

希望,它会解决你的问题。
另一答案我设法通过使用MediatorLiveData和Transformations解决了这个问题。
所以现在我的ViewModel构造函数如下所示:
public ExerciseViewModel(Application application) { super(application); this.repository = new ExercisesRepository(application); this.filterMutableLiveData = https://www.songbingjia.com/android/new MutableLiveData< > (); ExercisesFilter filter = new ExercisesFilter(); filter.muscleGroup =""; filter.type = ""; this.filterMutableLiveData.setValue(filter); LiveData< List< Exercise> > source = Transformations.switchMap( this.filterMutableLiveData, value -> repository.filterSelect(value.muscleGroup, value.type) ); this.data.addSource(source, val -> this.data.setValue(val)); }

我添加了这个方法:
public void setFilterMutableLiveData(String muscleGroups, String type) { ExercisesFilter filter1 = new ExercisesFilter(); filter1.muscleGroup = muscleGroups; filter1.type = type; this.filterMutableLiveData.setValue(filter1); }

使用此方法,每次更新过滤器时,都会触发传递给Transformations.switchMap的函数以获取新数据。最后,新的LiveData对象被添加到MediatorLiveData对象,因此可以将一个观察者用于所有源。
资料来源:https://github.com/googlesamples/android-sunflower/blob/99df6189af927b5cc477167923bbbd5a4ca1ece9/app/src/main/java/com/google/samples/apps/sunflower/viewmodels/PlantListViewModel.kt#L42

    推荐阅读