Что я делаю неправильно? Попытка извлечь данные из SQLite в AsyncTask, но он дает сбой - PullRequest
0 голосов
/ 10 июня 2019

В настоящее время я играю с Android - Room Persistence Library и пытаюсь получить не живые данные из базы данных SQLite, которые затем необходимо обработать и проверить по данным из Firestore Cloud. Все это выполняется в AsyncTask, но когда я пытаюсь получить данные из Room, я получаю следующую ошибку: "java.lang.IllegalStateException: не удается получить доступ к базе данных в главном потоке, так как он может потенциально заблокировать пользовательский интерфейс на длительный период времени.". Я понимаю, что я не могу вызвать метод базы данных из основного потока, но все это вызывается из AsyncTask, который должен обрабатывать все, что я сказал выше. Что я делаю не так?

Я попытался создать asyncTask в моем MainRepository, который в короткие сроки выглядит так:

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;
        }
    }

Это не сработало все время и в итоге дало некоторые измотанные результаты ...

Моя AsyncTask, где я пытаюсь извлечь данные из комнаты и сравнить с облаком Firestore, выглядит так:

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]);
        }
    }

1 Ответ

0 голосов
/ 11 июня 2019

При использовании get() на AsyncTask вы выполняете его синхронно . Это создаст работу в главном потоке, которая должна быть выполнена в другом потоке. Попробуйте удалить get() из функции вызова.

Согласно документации :

При необходимости ожидает завершения вычисления, а затем извлекает его результат.

...