Подтвердить что ты не робот

Метод asyncTask get(): Есть ли какой-либо сценарий, где это действительно лучший вариант?

После ответа на этот вопрос, я получил сомнение в смысле/полезности использования метода get() класса Android AsyncTask.

public final Result get ()

Waits if necessary for the computation to complete, and then retrieves its result. 

В принципе, это синхронное решение класса AsyncTask, которое блокирует (зависает) пользовательский интерфейс до завершения фоновых операций.

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

Если вам нужно, чтобы пользователь дождался завершения AsyncTask, вы можете показать Dialog или ProgressDialog, контролируя интерфейс пользователя в каждый момент. Я знаю, что это не совсем то же самое, но IMHO это гораздо лучший подход, чем метод get().

4b9b3361

Ответ 1

AsyncTask - не единственный способ делать фоновые операции. В самом деле, в документации говорится, что AsyncTask следует использовать только для выполнения операций не более нескольких секунд. Поэтому, если у вас есть задачи, которые занимают больше времени, они должны быть закодированы через классы, которые реализуют runnable interface. Такие задачи в других (не AsyncTask) потоках вполне могут подождать завершения AsyncTask, поэтому мне кажется, что идея о том, что нет ситуаций, в которых вы хотели бы использовать AsyncTask.get(), была ложной.

Обновление: В ответ на комментарий, чтобы подчеркнуть, что это может быть допустимым использованием AsyncTask.get(), возможно следующее:

  • Может быть AsyncTask, что инициировать из потока пользовательского интерфейса, который может включать обмен через Интернет, например загрузку веб-страницы или связь с сервером. Независимо от результатов AsyncTask, некоторые (или все) результаты необходимы для обновления экрана. Следовательно, AsyncTask с его doInBackground, за которым следует onPostExecute в потоке пользовательского интерфейса, имеет смысл.
  • Всякий раз, когда поток пользовательского интерфейса инициирует AsyncTask, он помещает объект AsyncTask в очередь, для дополнительной обработки отдельным фоновым потоком после получения результатов.
  • Для каждого AsyncTask в очереди, в свою очередь, фоновый поток использует AsyncTask.get() для ожидания завершения задачи, прежде чем выполнять дополнительная обработка. Один очевидный пример дополнительной обработки может просто регистрировать все такие действия AsyncTask на сервере в Интернете, поэтому имеет смысл сделать это в фоновом режиме.
Следующий код показывает, что я имею в виду. Приложение вызывает KickOffAsynctask(...) всякий раз, когда хочет сделать AsyncTask, и есть фоновый поток, который автоматически выполнит задачу для последующей обработки после завершения задачи.
public class MyActivity extends Activity {

    static class MyAsyncTaskParameters { }
    static class MyAsyncTaskResults { }

    Queue<MyAsyncTask> queue;   // task queue for post-processing of AsyncTasks in the background
    BackgroundThread b_thread;  // class related to the background thread that does the post-processing of AsyncTasks

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);     
        queue = new  ConcurrentLinkedQueue<MyAsyncTask>();
        b_thread = new BackgroundThread(queue);
        b_thread.Start();       
    }

    void KickOffAsynctask(MyAsyncTaskParameters params) {
        MyAsyncTask newtask = new MyAsyncTask();
        newtask.execute(params);
        synchronized(queue) {
            queue.add(newtask);
        }
    }

    static class MyAsyncTask extends AsyncTask<MyAsyncTaskParameters, Void, MyAsyncTaskResults> {

        @Override
        protected MyAsyncTaskResults doInBackground(MyAsyncTaskParameters... params) {
            MyAsyncTaskResults results = new MyAsyncTaskResults();
            // do AsyncTask in background
            return results;
        }

        @Override
        protected void onPostExecute(MyAsyncTaskResults res){
            // take required results from MyAsyncResults for use in the user interface
        }

    }

    static class BackgroundThread implements Runnable {
        // class that controls the post processing of AsyncTask results in background

        private Queue<MyAsyncTask> queue;
        private Thread thisthread;
        public boolean continue_running;

        public BackgroundThread(Queue<MyAsyncTask> queue) {
            this.queue=queue; thisthread = null; continue_running = true;
        }

        public void Start() {
            thisthread = new Thread(this);
            thisthread.start();
        }

        @Override
        public void run() {
            try {
                do {
                    MyAsyncTask task;
                    synchronized(queue) {
                        task = queue.poll();
                    }
                    if (task == null) {
                        Thread.sleep(100);
                    } else {
                        MyAsyncTaskResults results = task.get();
                        // post processing of AsyncTask results in background, e.g. log to a server somewhere
                    }
                } while (continue_running);     
            } catch(Throwable e) {
                e.printStackTrace();
            }           
        }

    }

}

Update2. Другое возможное использование AsyncTask.get() произошло со мной. Стандартный совет - не использовать AsyncTask.get() из потока пользовательского интерфейса, поскольку он заставляет пользовательский интерфейс зависеть, пока результат не будет доступен. Однако для приложения, где требуется скрытность, это может быть именно то, что требуется. Итак, как насчет следующей ситуации: Джеймс Бонд прорывается в гостиничный номер Le Chiffre и имеет только пару минут, чтобы извлечь все данные со звонкого телефона и установить вирус мониторинга. Он устанавливает приложение Q и запускает его, но он слышит, как кто-то идет, поэтому ему нужно скрыться. Le Chiffre входит в комнату и берет трубку, чтобы позвонить. На несколько секунд телефон кажется немного невосприимчивым, но вдруг телефон просыпается, и он делает свой телефонный звонок без дальнейших размышлений. Разумеется, причиной невнимательности было то, что приложение Q запущено. Ему приходилось выполнять различные задачи, и некоторые из них должны выполняться в определенном порядке. Приложение использовало два потока для выполнения работы, а именно сам пользовательский интерфейс и единственный фоновый поток, который обрабатывает AsyncTask s. Поток пользовательского интерфейса полностью контролировал все задачи, но поскольку некоторые задачи нужно было выполнять перед другими задачами, в приложении присутствовали точки, в которых поток пользовательского интерфейса использовал AsyncTask.get(), ожидая завершения фоновой задачи:-).

Ответ 2

Метод get никогда не должен использоваться в потоке пользовательского интерфейса, потому что он (как вы заметили) заморозит ваш пользовательский интерфейс. Он должен использоваться в фоновом потоке, чтобы дождаться конца вашей задачи, но, как правило, старайтесь избегать AsyncTask как можно больше (ПОЧЕМУ?).

Я бы предложил обратный вызов или eventbus в качестве замены.

Ответ 3

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

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

Ответ 4

Обычно я использую класс обработчика для выполнения трюка (загрузка асинхронного носителя). Как:

public void setRightSongAdele(Song current)
{
    RetriveCorrelateGenreSong rcgs = new RetriveCorrelateGenreSong(current);
    new Thread(rcgs).start();
}

@SuppressLint("HandlerLeak")
Handler updateRightAdeleHandler = new Handler()
{
    @Override
     public void handleMessage(Message msg) {
        songNextText.setText(utils.reduceStringLength(rightSong.getTitle(), 15));
        adeleNext.setImageBitmap(utils.getAlbumArtFromSong(rightSong.getPath(), getApplicationContext()));
    }
};

Ответ 5

Я отправляю свой собственный ответ, поскольку это то, что я думаю в этот момент, и никто его не дал.

Мое любопытство все еще живое, поэтому я не буду отмечать это как правильное. Если кто-то ответит на этот вопрос блестяще, я буду отмечать его/ее ответ как правильный.

Мой ответ заключается в том, что на самом деле нет сценария, когда использование метода AsyncTask get() является лучшим решением.

IMHO, использование этого метода бессмысленно. Я имею в виду, что всегда кажется лучшим решением.

Аналогично, я бы сказал, что это семантически шокирует, так как его обращение изменяет вашу AsyncTask в эффективную "SyncTask".

Ответ 6

Как документация стоит:

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

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

EDIT: я ошибся в NetworkOnMainThreadException.

Ответ 7

Кажется, что AsyncTask.get() блокирует поток вызывающего, где AsyncTask.execute() не делает.

Возможно, вы захотите использовать AsyncTask.get() для тестовых примеров, где вы хотите протестировать определенный вызов веб-службы, но вам не нужно, чтобы он был асинхронным, и вы хотите контролировать, сколько времени потребуется для завершения. Или в любое время, когда вы хотите протестировать веб-службу в тестовом пакете.

Синтаксис совпадает с исполнением:

    private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
    }

new DownloadFilesTask().get(5000, TimeUnit.MILLISECONDS);

Ответ 8

Вы можете использовать его в своем адаптере адаптера AutoCompleteTextView.

private class Adapter extends BaseAdapter implements Filterable{
    getFilter(){
        return new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            List<String> suggestions = MyApiSuggestionsApi(constraint).get();
            return packageAsFilterResults(suggestions);
        }
    }
}

Ответ 9

У меня есть приложение для редактирования фотографий, пользователь может открывать фотографии из URL-адресов.

Я использовал AsyncTask для загрузки фотографии с URL-адреса, в течение этого времени пользовательский интерфейс должен быть заблокирован. что я сделал, я показал, что ProgressBar запускает метод getyn() AsyncTask, чем скрывает ProgressBar..

Это казалось лучшим и самым простым решением для меня.