如何通过Repository和AsyncTask获取Room数据库插入返回的ID?
嘿,我来帮你解决这个问题!你现在的核心问题是异步插入操作完成后无法获取返回的ID,因为你的AsyncTask返回的是Void,而且Repository的insert方法是无返回值的,没法直接把ID传递回MainActivity。下面我给你两种可行的方案,其中更推荐符合Jetpack架构的LiveData方案,另外也会讲传统的回调方式,你可以根据需求选择。
先修复一个致命bug
你看你的CustomerRepository构造函数,先给mAllCustomers赋值,再初始化mCustomerDao,这会导致空指针异常,因为调用mCustomerDao.getAllCustomers()的时候mCustomerDao还没被实例化!必须调整顺序:
public CustomerRepository(Application application) { CustomerDatabase db = CustomerDatabase.getDatabase(application); // 先初始化Dao,再获取LiveData mCustomerDao = db.customerDao(); mAllCustomers = mCustomerDao.getAllCustomers(); }
方案一:用LiveData传递插入ID(推荐)
这种方式符合Android Jetpack的架构设计,利用LiveData的观察者模式来接收异步操作的结果,不需要写额外的回调接口,代码更简洁。
步骤1:修改Repository,添加LiveData存储插入ID
package com.example.jenso.paperseller; import android.app.Application; import android.arch.lifecycle.LiveData; import android.arch.lifecycle.MutableLiveData; import android.os.AsyncTask; import java.util.List; public class CustomerRepository { private CustomerDao mCustomerDao; private LiveData<List<Customer>> mAllCustomers; // 用来存储插入后的ID,用MutableLiveData以便修改值 private MutableLiveData<Long> mInsertedId = new MutableLiveData<>(); public CustomerRepository(Application application) { CustomerDatabase db = CustomerDatabase.getDatabase(application); mCustomerDao = db.customerDao(); mAllCustomers = mCustomerDao.getAllCustomers(); } LiveData<List<Customer>> getAllCustomers(){ return mAllCustomers; } // 暴露给ViewModel的LiveData,外部只能观察不能修改 public LiveData<Long> getInsertedId() { return mInsertedId; } public void insert (Customer customer){ new insertAsyncTask(mCustomerDao, mInsertedId).execute(customer); } // 注意AsyncTask的泛型改成<Customer, Void, Long>,返回Long类型的ID private static class insertAsyncTask extends AsyncTask<Customer, Void, Long> { private CustomerDao mAsyncTaskDao; private MutableLiveData<Long> mInsertedIdLiveData; insertAsyncTask(CustomerDao dao, MutableLiveData<Long> liveData) { mAsyncTaskDao = dao; mInsertedIdLiveData = liveData; } @Override protected Long doInBackground(final Customer... params) { // 调用Dao的插入方法,返回插入的ID return mAsyncTaskDao.insertAll(params[0]); } @Override protected void onPostExecute(Long id) { super.onPostExecute(id); // 异步操作完成后,把ID设置到LiveData中,通知观察者 mInsertedIdLiveData.setValue(id); } } // 修复delete方法,创建专门的DeleteAsyncTask public void delete(Customer customer) { new DeleteAsyncTask(mCustomerDao).execute(customer); } private static class DeleteAsyncTask extends AsyncTask<Customer, Void, Void> { private CustomerDao mAsyncTaskDao; DeleteAsyncTask(CustomerDao dao) { mAsyncTaskDao = dao; } @Override protected Void doInBackground(Customer... params) { mAsyncTaskDao.delete(params[0]); return null; } } }
步骤2:修改ViewModel,暴露InsertedId的LiveData
public class CustomerViewModel extends AndroidViewModel { private CustomerRepository mRepository; private LiveData<List<Customer>> mAllCustomers; private LiveData<Long> mInsertedId; public CustomerViewModel(Application application) { super(application); mRepository = new CustomerRepository(application); mAllCustomers = mRepository.getAllCustomers(); mInsertedId = mRepository.getInsertedId(); } LiveData<List<Customer>> getmAllCustomers() { return mAllCustomers; } public LiveData<Long> getInsertedId() { return mInsertedId; } public void insert(Customer customer) { mRepository.insert(customer); } // 其他方法... }
步骤3:在MainActivity中观察InsertedId
在onCreate方法里添加观察者,这样当插入完成后就能自动收到ID:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // ... 其他现有代码 // 观察插入ID的变化 mCustomerViewModel.getInsertedId().observe(this, new Observer<Long>() { @Override public void onChanged(@Nullable Long insertedId) { if (insertedId != null) { // 这里拿到了插入的ID,做你需要的操作 Log.d(TAG, "客户插入成功,ID:" + insertedId); Toast.makeText(MainActivity.this, "客户已保存,ID:" + insertedId, Toast.LENGTH_SHORT).show(); } } }); // ... 其他现有代码 }
然后修改onActivityResult里的调用,不需要再试图直接获取返回值:
public void onActivityResult(final int requestCode, final int resultCode, final Intent data){ super.onActivityResult(requestCode, resultCode, data); if (requestCode == NEW_CUSTOMER_ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK) { String[] mCustomerSave = data.getStringArrayExtra(CreateCustomer.EXTRA_REPLY); Customer customer = new Customer(mCustomerSave[0],mCustomerSave[1],mCustomerSave[2],mCustomerSave[3]); // 直接调用insert,观察者会自动处理结果 mCustomerViewModel.insert(customer); } else { Toast.makeText( getApplicationContext(), R.string.empty_not_saved, Toast.LENGTH_LONG).show(); } }
方案二:用回调接口传递ID
如果你更习惯传统的回调方式,也可以这样做:
步骤1:创建回调接口
在项目中新建一个接口(或者放在某个类里作为内部接口):
public interface InsertCallback { void onInsertSuccess(long insertedId); }
步骤2:修改Repository的insert方法和AsyncTask
public class CustomerRepository { // ... 其他现有代码 public void insert(Customer customer, InsertCallback callback) { new insertAsyncTask(mCustomerDao, callback).execute(customer); } private static class insertAsyncTask extends AsyncTask<Customer, Void, Long> { private CustomerDao mAsyncTaskDao; private InsertCallback mCallback; insertAsyncTask(CustomerDao dao, InsertCallback callback) { mAsyncTaskDao = dao; mCallback = callback; } @Override protected Long doInBackground(final Customer... params) { return mAsyncTaskDao.insertAll(params[0]); } @Override protected void onPostExecute(Long id) { super.onPostExecute(id); if (mCallback != null) { // 异步完成后调用回调,把ID传出去 mCallback.onInsertSuccess(id); } } } // ... 其他现有代码 }
步骤3:修改ViewModel的insert方法
public class CustomerViewModel extends AndroidViewModel { // ... 其他现有代码 public void insert(Customer customer, InsertCallback callback) { mRepository.insert(customer, callback); } // ... 其他现有代码 }
步骤4:在MainActivity中使用回调
public void onActivityResult(final int requestCode, final int resultCode, final Intent data){ super.onActivityResult(requestCode, resultCode, data); if (requestCode == NEW_CUSTOMER_ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK) { String[] mCustomerSave = data.getStringArrayExtra(CreateCustomer.EXTRA_REPLY); Customer customer = new Customer(mCustomerSave[0],mCustomerSave[1],mCustomerSave[2],mCustomerSave[3]); mCustomerViewModel.insert(customer, new InsertCallback() { @Override public void onInsertSuccess(long insertedId) { // 这里拿到ID Log.d(TAG, "插入成功,ID:" + insertedId); Toast.makeText(MainActivity.this, "客户已保存,ID:" + insertedId, Toast.LENGTH_SHORT).show(); } }); } else { Toast.makeText( getApplicationContext(), R.string.empty_not_saved, Toast.LENGTH_LONG).show(); } }
内容的提问来源于stack exchange,提问作者jenson4
相关产品推荐
相关产品推荐

