【发布时间】:2019-06-10 19:48:13
【问题描述】:
我目前正在使用 Android - Room Persistence Library,并尝试从 SQLite 数据库中检索非实时数据,然后需要根据 Firestore Cloud 中的数据对其进行处理和检查。所有这些都在 AsyncTask 中运行,但是当我尝试从 Room 检索数据时,出现以下错误:
java.lang.IllegalStateException:无法访问主线程上的数据库,因为它可能会长时间锁定 UI。
我知道我不能从主线程调用数据库方法,但所有这些都是从 AsyncTask 调用的,它应该处理我上面所说的所有内容。我做错了什么?
我试图在我的 MainRepository 中创建一个 asyncTask,简而言之,它看起来像这样:
public List<Shift> getAllShiftsForJobExport(int jobId){
try {
return new GetShiftsForJobAsync(shiftDao).execute(jobId).get();
} catch (ExecutionException e) {
e.printStackTrace();
return null;
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
}
这并不是一直有效,最终给出了一些奇怪的结果......
我试图从 Room 检索数据并与 Firestore 云进行比较的 AsyncTask 如下所示:
private static class DownloadDataFromCloud extends AsyncTask<Void, Void, Void> {
private CloudViewModel viewModel;
private FirebaseFirestore db;
private String userId;
DownloadDataFromCloud(FragmentActivity activity){
viewModel = ViewModelProviders.of(activity).get(CloudViewModel.class);
}
private void downloadData(){
List<Job> jobs = viewModel.getAllJobs();
Map<String, Job> jobDocuments = new HashMap<>();
for(Job job : jobs){
if(job.getDocumentId() != null){
jobDocuments.put(job.getDocumentId(), job);
}
}
CollectionReference jobsCollection = db.collection("jobs");
jobsCollection.whereEqualTo("userId", userId)
.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
for(QueryDocumentSnapshot documentSnapshot : queryDocumentSnapshots){
Job job = new Job();
job.convertCloudToObject(documentSnapshot);
if(jobDocuments.containsKey(job.getDocumentId())){
job.setId(jobDocuments.get(job.getDocumentId()).getId());
viewModel.updateJob(job);
downloadShiftData(job.getId(), job.getDocumentId());
}else {
viewModel.insertJobWithReturn(job, new AsyncResponse<Long>() {
@Override
public void processFinish(Long output) {
long jobId = output;
downloadShiftData((int) jobId, job.getDocumentId());
}
});
}
}
}
});
}
private void downloadShiftData(int jobId, String documentId){
List<Shift> shifts = viewModel.getAllShiftForJob(jobId);
Map<String, Shift> shiftDocuments = new HashMap<>();
for(Shift shift : shifts){
if(shift.getDocumentId() != null){
shiftDocuments.put(shift.getDocumentId(), shift);
}
}
CollectionReference shiftCollection = db.collection("shifts");
shiftCollection.whereEqualTo("userId", userId)
.whereEqualTo("jobDocumentId", documentId)
.get().addOnSuccessListener(queryDocumentSnapshots -> {
for (QueryDocumentSnapshot documentSnapshot : queryDocumentSnapshots) {
Shift shift = new Shift();
shift.convertCloudToObject(documentSnapshot);
if(shiftDocuments.containsKey(shift.getDocumentId())){
shift.setId(shiftDocuments.get(shift.getDocumentId()).getId());
viewModel.updateShift(shift);
}else {
shift.setJobId(jobId);
viewModel.insertShift(shift);
}
}
});
}
@Override
protected Void doInBackground(Void... voids) {
downloadData();
return null;
}
@Override
protected void onPreExecute() {
db = FirebaseFirestore.getInstance();
userId = FirebaseAuth.getInstance().getUid();
super.onPreExecute();
}
@Override
protected void onCancelled() {
super.onCancelled();
}
}
我得到的完整堆栈跟踪是:
java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
at androidx.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:228)
at androidx.room.RoomDatabase.query(RoomDatabase.java:255)
at androidx.room.util.DBUtil.query(DBUtil.java:54)
at com.*.daos.ShiftDao_Impl.getAllShiftsForJobExport(ShiftDao_Impl.java:909)
at com.*.MainRepository.getAllShiftsForJobExport(MainRepository.java:203)
at com.*.CloudViewModel.getAllShiftForJob(CloudViewModel.java:33)
at com.*.CloudHandler$DownloadDataFromCloud.downloadShiftData(CloudHandler.java:216)
at com.*.CloudHandler$DownloadDataFromCloud.access$300(CloudHandler.java:171)
at com.*.CloudHandler$DownloadDataFromCloud$1.onSuccess(CloudHandler.java:200)
at com.*.CloudHandler$DownloadDataFromCloud$1.onSuccess(CloudHandler.java:190)
at com.google.android.gms.tasks.zzn.run(Unknown Source:4)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
编辑 - GetShiftsForJobAsync 的代码:
private static class GetShiftsForJobAsync extends AsyncTask<Integer, Void, List<Shift>>{
private ShiftDao shiftDao;
GetShiftsForJobAsync(ShiftDao shiftDao){
this.shiftDao = shiftDao;
}
@Override
protected List<Shift> doInBackground(Integer... integers) {
return shiftDao.getAllShiftsForJobExport(integers[0]);
}
}
【问题讨论】:
-
将您的代码添加到您尝试获取数据的位置。您的错误清楚地表明您正在主线程上进行操作
-
@VedprakashWagh 我很快就发帖了,现在都更新了。
-
顺便说一句,您不需要添加 AsyncTask 来从 Firebase 获取数据。您可以在 UI 线程上直接运行代码以从 Firebase 数据库中获取数据。它在内部完成所有工作
-
@VedprakashWagh 我在 AsyncTask 中运行它的原因是因为我也在访问数据库,但它仍然给我错误,我不明白......
-
GetShiftsForJobAsync的代码在哪里?
标签: android android-asynctask android-room