Проверьте, завершены ли все AsyncTasks - PullRequest
20 голосов
/ 03 августа 2011

у меня 3 AsyncTasks и 1 ProgressBar.Я хочу, чтобы когда какая-либо из задач выполнялась, индикатор выполнения был виден, а когда все они заканчивались, индикатор выполнения был невидим.

В Java есть ExecutorService::isTerminated, чтобы проверить, все ли запущенные функции завершены, но Android не '

Обновление: 3 задачи выполняются одновременно.

Рисунок.enter image description here

Ответы [ 10 ]

22 голосов
/ 03 августа 2011

Хорошая графика. Но я боюсь, что для этого нет встроенного механизма. Вы должны будете реализовать это самостоятельно. Есть несколько решений, которые вы могли бы использовать -

  1. Сохраните ссылку на все 3 задачи. Когда задача завершится, проверьте, завершены ли две другие задачи, и если да, закройте диалоговое окно хода выполнения, если нет, дождитесь завершения другой задачи и проверьте снова. Убедитесь, что вы освободили ссылки, когда закончите.
  2. Если вы не хотите хранить в справочнике счетчик. Когда задача завершится, увеличьте счетчик и проверьте, равен ли он 3. Если все задачи завершены, и вы закончили. Если вы реализуете это, обязательно синхронизируйте доступ к счетчику.
7 голосов
/ 17 января 2013

Попробуйте использовать AsyncTask.getStatus (). Это прекрасно работает. Ниже приведен пример кода.

 List<AsyncTask<String, String, String>> asyncTasks = new ArrayList<AsyncTask<String, String, String>>();
 AsyncTask<String, String, String> asyncTask1 = new uploadTask().execute(string);
 AsyncTask<String, String, String> asyncTask2 = new downloadTask().execute(string);
 AsyncTask<String, String, String> asyncTask3 = new createTask().execute(string);
 asyncTasks.add(asyncTask1);
 asyncTasks.add(asyncTask2);
 asyncTasks.add(asyncTask3);

Позже вы можете выполнить цикл AsyncTaskList и найти статус каждой задачи, как показано ниже.

 for(int i=0;i<asyncTasks.size();i++){
      AsyncTask<String, String, String> asyncTaskItem = (AsyncTask<String, String, String>)asyncTasks.get(i);
      // getStatus() would return PENDING,RUNNING,FINISHED statuses
      String status = asyncTaskItem.getStatus().toString();
      //if status is FINISHED for all the 3 async tasks, hide the progressbar
 }
2 голосов
/ 03 августа 2011

Простой обходной путь - использовать три логические переменные по одной для каждой AsyncTask и затем проверять их соответствующим образом.

Лучшим подходом будет создание отдельного класса, расширяющего AsynTask и определяющего интерфейс обратного вызова,выстрелил в onPostExecute.

1 голос
/ 29 января 2013

создайте поле для хранения всех задач:

private ArrayList<HtmlDownloaderTask> mTasks;

Запустите ваши задачи следующим образом:

HtmlDownloaderTask = new HtmlDownloaderTask(page.getHtml());
task.execute(page.getUrl());
//if you want parallel execution try this:
//task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,page.getUrl());
mTasks.add(task);

на onPostExecute MyAsyncTask:

int unfinishedTasks = 0;
for (HtmlDownloaderTask myDT : mTasks){
    if(!(myDT.getStatus() == AsyncTask.Status.FINISHED)){
        unfinishedTasks++;
    }
}
if (unfinishedTasks == 1){
    //We are all done. 1 Because its the current one that hasnt finished post execute
    callWhateverMethod();

}
1 голос
/ 03 августа 2011

Ну, как вы знаете, когда заканчивается AsyncTask (когда вызывается onPostExecute): Одним из решений может быть создание метода setProgressBarVisible(), который сохраняет счетчик, а при первом вызове устанавливает видимый, и метод setProgressBarInvisible(), который уменьшает счетчик и когда ноль устанавливает индикатор выполнения невидимым.

0 голосов
/ 03 ноября 2018

Это распространенный вопрос, когда вы хотите запустить несколько 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, а если ваш пользовательский интерфейс мертв - что угодно.

0 голосов
/ 09 декабря 2016

Официальная поддержка CompletableFuture была введена начиная с уровня API 24.

Она также доступна в Java 8 здесь .

Можно использовать простоиспользуйте что-то вроде:

taskA.thenCombine(taskB).thenCombine(taskC)
0 голосов
/ 20 ноября 2015

Я бы просто уведомил об этом на onPostExecute(), см. onPostExecute и 4 шага в документе для получения подробной информации , и вы можете использовать EventBus, чтобы сделать некоторые вещи подписки.

0 голосов
/ 21 апреля 2015

попробуйте это, может быть, может помочь вам ...

            final ImageUploader _upload = new ImageUploader();
            _upload.setValue(getApplicationContext(), _imagepath, _urlPHP);
            _upload.execute();
            Runnable _run;
            Handler _h2;
            _run = new Runnable() {
                public void run() {
                    _h2 = new Handler();
                    _h2.postDelayed(this, 1000);
                    Toast.makeText(getApplicationContext(), "not finished", Toast.LENGTH_LONG).show();

                    if (_upload.getStatus() == AsyncTask.Status.FINISHED) {
                        Toast.makeText(getApplicationContext(), "finished", Toast.LENGTH_LONG).show();
                        _h2.removeCallbacks(_run);

                    }
                }
            };
            _h2 = new Handler();
            _h2.postDelayed(_run, 1);
0 голосов
/ 22 марта 2012

: -?Я думаю, что это просто трюк.Вы вернете какое-то сообщение на onPostExecute каждого Asyntask и сравните его.(это сообщение может содержать время, например)

...