学向勤中得,萤窗万卷书。这篇文章主要讲述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
推荐阅读
- 设计AppServer面试讨论
- Android运行时权限对话框未显示
- 为什么选择Android应用程序项目的Kotlin()
- 如何在Visual Studio Community 2017中更改为深色主题
- 如何确定数字是否为C中的阿姆斯特朗数
- 如何在Swift中打印Pascal三角形
- 如何在C ++中打印Pascal三角形
- 如何使用Microsoft SQL Server Management Studio 17将MS SQL Server数据库导出到SQL脚本(数据库到sql文件)
- 如何在Swift中使用打印功能在没有换行的情况下将内容打印到控制台