Почему?
По сути, это было написано в документации AsyncTask : все асинхронные задачи выполняются последовательно в уникальном фоновом потоке .
Мой код, даже без вложенной асинхронной задачи, блокировал этот поток практически бесконечной задачей, задерживая все операции с базой данных до ее завершения (или сбоя приложения, что привело к некоторой потере данных).
Быстрое решение: перемещение AsyncTask в поток
Другие альтернативы были приятно перечислены (CommonsWare) [https://stackoverflow.com/a/56925864/9138818], Вот шаги, которые я предпринял, чтобы решить эту проблему.
Основная трудность заключалась в том, чтобы перенаправить код, который выполнялся в потоке пользовательского интерфейса (onPreExecute, onProgressUpdate, onPostExecute), через обработчик , связанный с основным потоком.
Первым шагом было получение ссылки на обработчик:
// Inside Runnable task's constructor :
// get the handler of the main thread (UI), needed for sending back data.
this.uiHandler = new Handler(Looper.getMainLooper());
Затем рефакторинг doInBackground соответствует сигнатуре основного метода Runnable:
// previously "public String doInBackground()"
// returned value handled through publishProgress.
@Override
public void run() {
// recommended by Android Thread documentation
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// code previously in doInBackground
Теперь код в onProgressUpdate (который был вызван publishProgress внутри метода doInBackground) был перемещен в Runnable, размещенный в обработчике потока пользовательского интерфейса:
// asynctask method onProgressUpdate was renamed publishProgress =>
// doInBackground's body is almost untouched.
private void publishProgress(final OnProgressObject... values) {
uiHandler.post(new Runnable() {
@Override
public void run() {
// move here code previously in the AsyncTask's publishProgress()
}
});
}
Наконец, мне пришлось изменить способ создания, запуска и остановки задачи, используя Thread.interrupted
вместо isCancelled
и создав задачу Runnable перед потоком:
public void startCUBMonitoring() {
if (autoEventThread == null) {
Log.d(LOG_TAG, "startCUBMonitoring");
addUIEvent("CUB MONITORING STARTED", "CUB_connexion");
SessionRepository sessionRepository =
ElabsheetApplication.getInstance().getSessionRepository();
// Creation of the task
AutoEventTask autoEventTask = new AutoEventTask(
this,
sessionRepository,
sessionRepository.getCUBConfig()
);
autoEventThread = new Thread(autoEventTask);
autoEventThread.start();
}
}
public void stopCUBMonitoring() {
if (autoEventThread != null) {
Log.d(LOG_TAG, "stopCUBMonitoring");
addUIEvent("CUB MONITORING STOPPED", "CUB_connexion");
autoEventThread.interrupt();
autoEventThread = null;
}
}
Надеялся, что это может помочь ...