Это распространенный вопрос, когда вы хотите запустить несколько AsynTasks для THREAD_POOL_EXECUTOR. Это намного быстрее, чем если бы вы просто позвонили .execute()
, и все ваши задачи выполнялись одна за другой.
Поэтому, если у вас есть несколько заданий и объекты не зависят друг от друга, попробуйте запустить в пуле потоков.
Но вопрос в том, откуда мне знать, что все мои задачи выполнены.
В AsyncTask нет встроенных методов, поэтому вы должны сделать небольшой обходной путь.
В моем случае я добавил статическое поле Hashmap в свой класс Asynctask, чтобы отслеживать все запущенные и завершенные задачи. В качестве бонуса карты я всегда могу знать, какое задание выполняется в данный момент.
private static HashMap<Uri, Boolean> mapOfAttachmentTasks = new HashMap<>();
и три простых способа доступа к этой карте.
Важно: они должны быть синхронизированы
public static synchronized void addTask(Uri uri){
mapOfAttachmentTasks.put(uri, true);
}
public static synchronized void removeTask(Uri uri){
mapOfAttachmentTasks.remove(uri);
}
public static synchronized boolean isTasksEmpty(){
return mapOfAttachmentTasks.isEmpty();
}
Вы хотите добавить новый элемент на карту отслеживания в конструкторе AsyncTask и удалить его в onPostExecute ():
public AttachmentTask(Uri uri) {
this.uri = uri;
addTask(uri);
}
@Override
protected void onPostExecute(Attachment attachment) {
removeTask(uri);
if(isTasksEmpty())
EventBus.getDefault().post(new AttachmentsTaskFinishedEvent(attachment));
}
Каждый раз, когда задача завершается, она вызывает метод PostPexecute, и вы проверяете, была ли она последней. Если заданий не осталось - отправьте сигнал, что вы сделали.
Теперь я использовал EventBus для отправки события в мой фрагмент, но вы можете использовать обратный вызов. В этом случае вы должны создать интерфейс с callbackMethod, ваш фрагмент (любой из ваших компонентов пользовательского интерфейса, ожидающих событие) должен реализовать этот интерфейс и иметь этот метод. Затем в конструкторе AsyncTask вы получаете ваш Fragment в качестве аргумента и сохраняете ссылку на него, так что вы можете вызвать его метод обратного вызова, когда все будет сделано.
Но мне не нравится такой подход. Сначала вам нужно сохранить ссылку на ваш фрагмент (или любой другой пользовательский интерфейс) в оболочке WeakReference, потому что вы получите утечку памяти, когда ваш фрагмент мертв (но все еще хранится в памяти, потому что ваш AsyncTask имеет свою ссылку).
Также вам нужно будет сделать много проверок, и это будет выглядеть примерно так:
private boolean isAlive() {
return mFragmentWeakReference != null
&& mFragmentWeakReference.get() != null
&& mFragmentWeakReference.get().isAdded()
&& mFragmentWeakReference.get().getActivity() != null
&& !mFragmentWeakReference.get().getActivity().isFinishing();
Да, в производстве вы должны быть немного параноиком и делать все эти проверки:)
Вот почему вы можете использовать EventBus, а если ваш пользовательский интерфейс мертв - что угодно.