[英]Android application with MVVM architecture, writing to local Room database from a Service using MVVM, how should the Service write to the database?
[英]How to make Room database insert method return int through mvvm architecture?
我想在Room数据库上执行插入操作时自动生成ID。 我正在实现MVVM(模型-视图-视图模型)体系结构,该体系结构使用DAO向Room数据库发出查询。 我在viewmodel和DAO之间添加了一个存储库层,以创建一个AsyncTask来执行数据库操作。 如何获取对使用viewmodel的片段的插入操作(插入行的自动生成的ID)的输出。 这些层如下:片段-> ViewModel->存储库-> 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]);
}
}
}
提醒DAO.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方法返回它?
您可以以自动增加id
的方式创建database
表。 在MySQL中,是通过auto_increment
关键字完成的。 在SQL Server中,这是通过identity(1, 1)
语法完成的。 在Access中,它是autoincrement
关键字。 在Oracle和PostgreSQL中,使用sequence
s完成。 如果您能够做到这一点,那么您将不需要手动增加这些值。 如果出于某种原因这是不可能的,那么您可以创建一个before insert
触发器,该触发器将加载最大ID并将其添加1,并将结果存储在ID中。 或者,即使这是不可能的,您也可以加载最后一个ID,但是在不同的数据库中它具有不同的语法。 或者,您可以运行如下查询:
select max(id) + 1 from yourtable;
但要注意可能的性能问题和并发问题。
我有确切的问题。 这就是我所做的。
我创建了一个界面
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返回给活动或片段,则让片段/活动实现接口而不是viewmodel
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)
}
修改视图模型中的insert fcn以接受对接口的引用
public void insertMyObject(MyObject object, Task myInterface){
mRepository.insertMyObject(object,myInterface);
}
通过这种方法,存储库插入文件fcn中的asynctask将保存对活动/片段的引用,并且如果在asynctask完成之前销毁了活动/片段,将是一个问题。 我认为最好在视图模型中进行处理。 片段/活动应仅处理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
}
在活动/片段的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
}
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.