最佳实践:使用Room和LiveData运行时过滤器

Ode*_*rik 14 android mvvm android-room android-livedata

我正在使用回收器显示Room wrapped DB的内容的屏幕上.适配器从ViewModel获取LiveData,该ViewModel隐藏Room DAO对象上的查询调用.因此,LiveData对象实际上是一个ComputableLiveData对象,它知道Room DB的更改.

现在我想在屏幕上添加过滤器选项.我在何处/如何在Room-LiveData-ViewModel设置中实现此功能?

适配器或ViewModel应该"postfilter"结果在LiveData中吗?我是否应该为每次过滤器更改从房间重新查询数据?我可以重用底层(可计算)LiveData吗?如果没有,我是否真的应该为每个过滤器更改创建新的LiveData?

此处讨论了类似的问题:使用Room,ViewModel和LiveData更改数据后重新加载RecyclerView

Fra*_*ior 13

我正在处理类似的问题.最初我有RxJava但现在我将它转换为LiveData.

这就是我在ViewModel中的做法:

// Inside ViewModel
MutableLiveData<FilterState> modelFilter = new MutableLiveData<>();
LiveData<PagedList<Model>> modelLiveData;
Run Code Online (Sandbox Code Playgroud)

此modelReivedata在视图模型构造函数中按以下方式构造:

        // In ViewModel constructor
        modelLiveData = Transformations.switchMap(modelFilter,
                    new android.arch.core.util.Function<FilterState, LiveData<PagedList<Model>>>() {
                        @Override
                        public LiveData<PagedList<Model>> apply(FilterState filterState) {
                            return modelRepository.getModelLiveData(getQueryFromFilter(filterState));
                        }
                    });
Run Code Online (Sandbox Code Playgroud)

当视图模型接收另一个要应用的过滤器时,它会:

// In ViewModel. This method receives the filtering data and sets the modelFilter 
// mutablelivedata with this new filter. This will be "transformed" in new modelLiveData value.
public void filterModel(FilterState filterState) {

    modelFilter.postValue(filterState);
}
Run Code Online (Sandbox Code Playgroud)

然后,这个新过滤器将被"转换"为一个新的有望数值,该值将被发送给观察者(一个片段).

片段通过视图模型中的调用获取要观察的livingata:

// In ViewModel
public LiveData<PagedList<Model>> getModelLiveData() {

    return modelLiveData;

}
Run Code Online (Sandbox Code Playgroud)

在我的片段中,我有:

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    ViewModel viewModel = ViewModelProviders.of(this.getActivity()).get(ViewModel.class);

    viewModel.getModelLiveData().observe(this.getViewLifecycleOwner(), new Observer<PagedList<Model>>() {
        @Override
        public void onChanged(@Nullable PagedList<Model> model) {
            modelListViewAdapter.submitList(model);
        }
    });

}
Run Code Online (Sandbox Code Playgroud)

我希望它有所帮助.


Ode*_*rik 5

所以,我最终这样做了:

  • 该片段将过滤器状态转发给 ViewModel。副作用:过滤器状态可能被多个(即由于配置更改而导致的后续)片段实例使用。也许你想要那个,也许不。我愿意。
  • ViewModel 拥有一个 MediatorLiveData 实例。它有一个来源:Room DB LiveData 对象。源只是将更改转发给中介。如果片段更改了过滤器,则通过重新查询来交换源。

回答我的详细问题:

  • 无后置过滤
  • 是的,重新查询过滤器更改
  • 我不重用 ComputableLiveData(不确定是否有可能)

关于评论中的讨论:

  • 我不应用分页

关于 Room 的最后说明:我错了还是我需要为我想要应用的每个过滤器组合编写单独的 DAO 方法?好的,我可以通过 String 插入 select 语句的可选部分,但是我会失去 Room 的好处。某种使语句可组合的语句生成器会很好。

编辑:请注意下面 Ridcully 的评论。他提到 SupportSQLiteQueryBuilder 和 @RawQuery 来解决我猜的最后一部分。不过我还没有检查出来。

感谢CommonsWare和pskink的帮助!

  • 有 SupportSQLiteQueryBuilder,你可以在 DAO 中与 @RawQuery 一起使用。 (3认同)