直接使用Room的劣势
Android在UI线程不能执行耗时操作,在工作线程不能刷新UI(别在这抬杠,我知道一些情况下可以)而我们的数据更新变化了自然需要给用户展示出来看,但是数据变化又在工作线程,这就涉及到线程间通信,很不方便。虽然我们有Hander,AsyncTask,runOnUiThread
等等很多好用的原生支持,甚至还有很多第三方库,但这些目前看来都不是最优解。
解决方案
-
在以往我们数据发生变化时都需要再去在工作线程中查询一遍数据然后把数据再给到UI线程去刷新,但是现在我们希望数据发生变化时,能自动接收到通知拿到最新数据,怎么搞?
LiveData
帮我们来搞定,这样当Room数据库中的数据发生变化时,通过LiveData
组件通知View层,就可以实现数据的更新了。 -
LiveData
通常与ViewModel
一起使用,ViewModel
是用于存放数据的,因此我们可以将数据库放在ViewModel
中进行实例化,但数据库的实例化需要用到Context,而ViewModel
中最好不要传入Context,因此直接使用ViewModel
不妥,那我们使用它的子类AndroidViewModel
,其构造方法中含有Application参数,其作为Context的子类刚好可以用来初始化数据库实例。
案例优化
请先阅读上篇,点击这里
-
修改三国人物表的Dao文件,我们希望当数据发生变化时,能够收到一个实时的通知,这里用
LiveData
将数据进行包装,如下:@Dao public interface EmperorDao { //删除了上篇中的代码 //使用LiveData将结果List<Emperor>包装起来 @Query("SELECt * FROM emperor_table") public LiveData<List<Emperor>> queryEmperorsByLiveData(); }
-
创建
EmperorViewModel
类,在构造器中初始化数据库,并且用LiveData
包装Listpublic class EmperorViewModel extends AndroidViewModel { private MyDatabase myDatabase; //用LiveData包装List<Emperor> private LiveData<List<Emperor>> listEmperor; public EmperorViewModel(@NonNull Application application) { super(application); //初始化数据库实例 myDatabase = MyDatabase.getDatabaseInstance(application); listEmperor = myDatabase.getEmperorDao().queryEmperorsByLiveData(); } public LiveData<List<Emperor>> getListEmperor() { return listEmperor; } }
-
在Activity/Fragment中实例化
EmperorViewModel
,并监听LiveData
中数据的变化EmperorViewModel emperorViewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication())).get(EmperorViewModel.class); emperorViewModel.getListEmperor().observe(this, new Observer<List<Emperor>>() { @Override public void onChanged(List<Emperor> emperors) { //do what you need } });
结论
运行程序,当数据库每次数据有变动时,onChanged
方法会被自动调用,在此方法中刷新数据即可,不需要自己再去开子线程和交换数据了。