java - 如何通过 mvvm 架构使 Room 数据库插入方法返回 int?
问题描述
我想在 Room 数据库上执行插入操作时自动生成 id。我正在实现 MVVM (Model-View-ViewModel) 架构,它使用 DAO 来触发对 Room 数据库的查询。我在 viewmodel 和 DAO 之间添加了一个存储库层来创建一个 AsyncTask 来执行数据库操作。如何将插入操作的输出(即插入行的自动生成的 id)获取到使用视图模型的片段。层如下:Fragment -> ViewModel -> Repository -> DAO
ListFragment.java
public class ListFragment extends Fragment {
private ReminderViewModel viewModel;
private int id;
...
viewModel = ViewModelProviders.of(this).get(ReminderViewModel.class);
...
id = viewModel.insert(new TodoReminder(0, description, date, time));
...
}
ReminderViewModel.java
public class ReminderViewModel extends AndroidViewModel {
private ReminderRepository repository;
public ReminderViewModel(@NonNull Application application) {
super(application);
repository = new ReminderRepository(application);
}
public int insert(TodoReminder reminder) {
repository.insert(reminder);
}
}
ReminderRepository.java
public class ReminderRepository {
private ReminderDAO reminderDAO;
public ReminderRepository(Application application) {
AppDatabase db = AppDatabase.getDatabase(application);
reminderDAO = db.getReminderDAO();
}
public int insert(TodoReminder reminder) {
new insertAsyncTask(reminderDAO).execute(reminder);
}
private static class InsertAsyncTask extends AsyncTask<TodoReminder, Void, Integer> {
private ReminderDAO asyncTaskDAO;
insertAsyncTask(ReminderDAO dao) {
asyncTaskDAO = dao;
}
@Override
protected Integer doInBackground(final TodoReminder... reminders) {
return asyncTaskDAO.insert(reminders[0]);
}
}
}
ReminderDAO.java
@Dao
public interface ReminderDAO {
@Insert
public int insert(TodoReminder... reminders);
}
ToDoReminder.java
public class TodoReminder implements Serializable {
@PrimaryKey(autoGenerate = true)
@NonNull
private int id;
...
}
我应该如何获取从 ReminderDAO 的 insert 方法返回的 int 并从 ReminderRepository 的 insert 方法返回?
解决方案
我有确切的问题。这就是我所做的。
我创建了一个界面
public interface Task
{
void processInsert(long id)
}
在存储库中提供插入 fcn 的接口
public class Repository {
private Dao myDao;
public void insertMyObject(MyOBject object,Task myInterface ) {
new insertAysncTask(myDao,myInterface).execute(object);
}
private static class insertAsyncTask extends AysncTask<MyObject,Void,Long>{
private Dao mDao;
private Task mTask;
public insertAysncTask(Dao dao, Task task) {
this.mDao = dao;
this.mTask=task;
}
@Override
protected Long doInBackground(MyObject... myObjects) {
return mDao.insertMyObject(myObjects[0]);
}
@Override
protected void onPostExecute(Long aLong) {
super.onPostExecute(aLong);
mTask.processInsert(aLong);
}
}
}
在 DAO 类 fcn 中的返回类型应该是 Long
public interface MyDao {
@Insert
Long insertMyObject(MyObject object);
让 ViewModel 实现接口
public class MyObjectViewModel extends AndroidViewModel implements Task{
private Repository mRepository;
public MyObjectViewModel(@NonNull Application application) {
super(application);
mRepository = new Repository(application);
}
@Override
public void processInsert(Long id) {
// code for processing the id returned from the db insert
}
public void insertMyObject(MyObject object){
mRepository.insertMyObject(object,this);}
}
在活动/片段中调用 ViewModel 插入
mViewModel.insertMyObject(object);
更新
如果您想将 id 返回给活动或片段,则让片段/活动实现接口而不是视图模型
ListFragment extends Fragment implements Task{
.....
@Override
public void processInsert(Long id){
//process id here
}
//call the insert fcn passing in the reference to the fragment
mViewModel.insertMyObject(object,this)
}
修改 View Model 中的 insert fcn 以接受对接口的引用
public void insertMyObject(MyObject object, Task myInterface){
mRepository.insertMyObject(object,myInterface);
}
使用这种方法,存储库 insert fcn 中的异步任务将保存对活动/片段的引用,如果活动/片段在异步任务完成之前被销毁,这将是一个问题。我认为如果可能的话,最好在视图模型中进行处理。片段/活动应该只处理 UI 问题而不是数据处理。
替代方法 另一种方法是将 LiveData 与观察者一起使用。
public class Repository{
private Dao myDao;
private MutableLiveData<Long> dbInsertId = new MutableLiveData<>();
public void insertMyObject(MyObject object){
insertAysnc(object)
}
private void insertAysnc(final MyObject object){
new Thread(new Runnable() {
@Override
public void run() {
Long id=myDao.insertMyObject(object); //call Dao insert fcn
dbInsertId.postValue(id); //set the value of the livedata to the valued returned from the DB insert fcn
}
}).start();
}
public LiveData<Long> getDbInsertedId(){
return dbInsertId;
}
}
在 ViewModel 中定义这个 fcn
public LiveData<Long> getDbInsertedId(){
return mRepository.getDbInsertedId();// call the repository getId fcn
}
在 Activity/Fragment 的 onCreate 中设置 LiveData 上的观察者
mViewModel= ViewModelProviders.of(this).get(MyViewModel.class);
mViewModel.getDbInsertedId().observe(this, new Observer<Long>() {
@Override
public void onChanged(Long aLong) {
// do something with the long value returned from the database
}
});
推荐阅读
- arrays - Array1 由可被 3 整除的数字组成。创建一个 array2,其中第一个元素是奇数,然后是偶数
- interrupt - RISC-V - 软件中断
- arrays - 在类对象列表中查找用户名
- javascript - 如何使用 Paypal 为 Google Pay 执行授权 + 捕获流程?
- node.js - 类型“用户 []”.ts(2339) 上不存在属性“密码”
- javascript - 为什么我不能让这些卡片排成一行。他们不断地落入一列
- javascript - lodash groupBy 行为
- python - 删除异常值以通过箱线图计算系列/数据框的平均值?
- json - 在 Flutter 中创建 JSON 数组
- react-native - 应用程序后台运行时无法使任何传感器工作 [Expo (React-Native)]