Подробное объяснение 6 реализаций асинхронных задач Android.

Подробное объяснение 6 реализаций асинхронных задач Android.


Поток пользовательского интерфейса Android (основной поток) имеет несколько характеристик:

  • Представление пользовательского интерфейса может работать только в потоке пользовательского интерфейса, а не в подпотоках.
  • В потоке пользовательского интерфейса нельзя выполнять трудоемкие операции, иначе поток пользовательского интерфейса будет заблокирован, что вызовет такие проблемы, как ANR и зависание.

В разработке для Android мы обычно используем асинхронные задачи для обработки некоторых трудоемких операций. Например, в таком сценарии дочерний поток выполняет асинхронную задачу в фоновом режиме. Во время процесса задачи процесс пользовательского интерфейса должен отображать ход выполнения. В настоящее время нам нужен инструмент для реализации этого требования. Система Android предоставляет разработчикам класс асинхронных задач (AsyncTask) для реализации вышеперечисленных функций, то есть он будет выполнять вычислительные задачи в подпотоке, и в то же время получать возможность обновлять интерфейс приложения через цикл сообщений основного потока.

Какие асинхронные задачи обычно используются в разработке для Android?

1. Создано с помощью Thread

Самый прямой способ — использовать класс Thread, предоставляемый Java, для создания потоков для достижения асинхронности.

Чтобы узнать, как создать поток, обратитесь к «Обзору трех способов создания потоков в Java» .

2. Поток + Looper + обработчик

Android предоставляет механизм Handler для связи между потоками, мы можем использовать самый простой асинхронный метод Android: Thread + Looper + handler для выполнения асинхронных задач.

Принципы механизмов, связанных с обработчиком, см. в статье: «Механизм связи потока обработчика: реальный бой, принципы и оптимизация производительности!» "

Образец кода:

Handler mHandler = newHandler(){
    @Override
    publicvoid handleMessage(Message msg){
        if(msg.what == 1){
            textView.setText("Task Done!!");
        }
    }
};
mRunnable = new Runnable() {
    @Override
    publicvoid run() {
        SystemClock.sleep(1000);    // 耗时处理
        mHandler.sendEmptyMessage(1);  
    }
};
private void startTask(){
    new Thread(mRunnable).start();
}

преимущество:

  • Операция проста и не требует затрат на обучение.

недостаток:

  • Код плохо стандартизирован и сложен в обслуживании.
  • Каждая операция открывает анонимный поток, а системные накладные расходы велики.

3. Асинхронная задача

Относительно легкий асинхронный класс, который инкапсулирует пул потоков FutureTask, ArrayDeque и Handler для планирования. AsyncTask в основном используется для непрерывного взаимодействия между фоном и интерфейсом.

Давайте посмотрим на определение абстрактного класса AsyncTask.Когда мы определяем класс, который наследует класс AsyncTask, нам нужно указать для него три общих параметра:

AsyncTask <Params, Progress, Result>

  • Params: этот универсальный определяет тип параметров, которые мы передаем для выполнения асинхронной задачи.
  • Ход выполнения: этот общий тип указывает тип параметра, который наша асинхронная задача будет возвращать потоку пользовательского интерфейса при выполнении хода выполнения.
  • Результат: тип результата, возвращаемый потоку пользовательского интерфейса после выполнения асинхронной задачи, заданной этим универсальным типом.

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

Давайте посмотрим на официальный пример:

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));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }
     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }
     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
}

При его использовании вам нужно только интегрировать AsyncTask, создать объект и вызвать execute для выполнения:

new DownloadFilesTask().execute(url1, url2, url3);

Выполните трудоемкую логику в методе doInBackground(Params…), а затем обновите результат обратно в компонент пользовательского интерфейса в onPostExecute(Result)

Среди основных методов AsyncTask метод doInBackground выполняется в дочернем потоке, а методы execute, onPreExecute, onProgressUpdate и onPostExecute выполняются в потоке пользовательского интерфейса.

Примечания по использованию AsyncTask

  • Экземпляр AsyncTask должен быть создан в потоке пользовательского интерфейса.
  • Метод выполнения AsyncTask можно вызывать только из потока пользовательского интерфейса.
  • Четыре переопределенных метода AsyncTask автоматически вызываются системой и не должны вызываться вручную.
  • Каждая AsyncTask может быть выполнена только один раз, многократное выполнение вызовет исключение.
  • Из четырех методов AsyncTask только метод doInBackground выполняется в других потоках, а остальные три метода выполняются в потоке пользовательского интерфейса, что означает, что остальные три метода могут выполнять операции обновления пользовательского интерфейса.
  • По умолчанию AsyncTask выполняется последовательно, если требуется параллельное выполнение, используйте интерфейсный метод executeOnExecutor.

преимущество:

  • Четкая структура, простой в использовании, подходит для взаимодействия с фоновыми задачами.
  • Приоритет асинхронного потока был установлен по умолчанию: THREAD_PRIORITY_BACKGROUND, который не будет захватывать ресурсы потоком пользовательского интерфейса.

недостаток:

  • Структура немного сложнее, а кода больше.
  • Каждая AsyncTask может быть выполнена только один раз, и при многократном вызове возникнет исключение.
  • AsyncTask поддерживает пул потоков во всей системе Android, который может быть вытеснен задачами других процессов и снижать эффективность.

Примечание. Принцип работы AsyncTask и другие подробности см. в разделе «Вы действительно знаете, как использовать AsyncTask?» Реальный бой, принцип, лучшая практика! (Android Q)" .

4. Обработчикпоток

HandlerThread — это класс потока с собственным циклом обработки сообщений Looper. Способ обработки асинхронных задач такой же, как Thread + Looper + Handler.

преимущество:

  • Простой, цикл сообщений Looper обычных потоков реализован внутри.
  • Несколько задач могут выполняться последовательно.
  • Он имеет свою собственную очередь сообщений внутри и не будет блокировать поток пользовательского интерфейса.

недостаток:

  • Если в интерфейс не возвращается результат, он должен быть обработан сам по себе.
  • Когда сообщений слишком много, легко вызвать блокировку.
  • Существует только одна обработка потока, которая менее эффективна.
  • Приоритет потока. Приоритет по умолчанию — THREAD_PRIORITY_DEFAULT, что упрощает вытеснение ресурсов из потока пользовательского интерфейса.

Примечание. Для получения более подробной информации см.: «Принципиальный анализ HandlerThread, реальный бой, передовой опыт!» " .

5. Служба намерений

IntentService наследуется от класса Service и используется для запуска асинхронной задачи службы.Он реализует задачи асинхронной обработки внутри себя через HandlerThread.

Давайте посмотрим на основной метод IntentService:

    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

преимущество:

  • Вам нужно только наследовать IntentService, и вы можете асинхронно обрабатывать задачи типа Intent в методе onHandlerIntent.
  • После завершения задачи IntentService остановится сам по себе, нет необходимости вызывать stopService вручную.
  • Он может обрабатывать несколько запросов Intent и последовательно выполнять несколько задач.
  • IntentService наследуется от Service и имеет приоритет над фоновой службой.

недостаток:

  • Необходимо запустить службу для выполнения асинхронных задач, не подходящих для простой обработки задач.
  • Асинхронные задачи реализуются HandlerThread, который может обрабатывать задачи только в одном потоке и последовательно.
  • Обратного интерфейса к потоку пользовательского интерфейса нет.

6. Используйте пул потоков для обработки асинхронных задач

Используйте статические методы newCachedThreadPool(), newFixedThreadPool(), newSingleThreadExecutor() и перегруженные формы Executors для создания экземпляра интерфейса ExecutorService для получения объекта пула потоков.

  • Динамический пул потоков newCachedThreadPool(): создает новые потоки в соответствии с потребностями. Когда потребность велика, будет создано больше. Когда потребность мала, JVM будет медленно освобождать избыточные потоки.
  • Фиксированное количество пулов потоков newFixedThreadPool(): Внутри находится очередь блокировки задач.Предположим, что в пуле потоков 2 потока и отправлено 4 задачи, тогда последние две задачи будут помещены в очередь блокировки задач, даже если первые 2 задачи спят. Или, если он заблокирован, последние две задачи не будут выполняться, пока не будут выполнены первые две задачи.
  • Однопоточный newSingleThreadExecutor(): однопоточный пул потоков, этот пул потоков может перезапускать поток после того, как поток умирает (или когда возникает исключение), чтобы заменить исходный поток и продолжить выполнение.

преимущество:

  • Создание и уничтожение потоков поддерживается пулом потоков, который реализует повторное использование потоков, тем самым уменьшая накладные расходы на создание и уничтожение потоков.
  • Он подходит для выполнения большого количества асинхронных задач и повышения производительности.
  • Высокая гибкость, вы можете свободно контролировать количество потоков.
  • Хорошая масштабируемость, может быть расширена в соответствии с реальными потребностями.

недостаток:

  • Код немного сложнее.
  • Сам пул потоков в определенной степени потребляет системные ресурсы.
  • Когда потоков слишком много, стоимость переключения между потоками будет очень высокой, что серьезно снизит производительность.
  • Каждый поток потребляет не менее 1040 КБ памяти, а количество потоков в пуле потоков необходимо контролировать в определенном диапазоне.
  • Приоритет потока наследуется.Если пул потоков создается в потоке пользовательского интерфейса, приоритет потока по умолчанию будет таким же, как и у потока пользовательского интерфейса, тем самым вытесняя ресурсы, используемые потоком пользовательского интерфейса.

Подведем итог


В этой статье подробно представлены шесть способов реализации асинхронных задач в Android:

  1. Создано с использованием потока
  2. Используйте Thread + Looper + обработчик
  3. Используйте асинхронную задачу
  4. Использовать обработчикпоток
  5. Использовать IntentService
  6. Используйте пул потоков для обработки асинхронных задач

При этом мы также проанализировали сценарии использования каждого метода, его преимущества и недостатки.


**PS: Чтобы увидеть больше интересного контента, просмотрите --> "Разработка Android"
**PS: Чтобы увидеть больше интересного контента, просмотрите --> "Разработка Android"
**PS: Чтобы увидеть больше интересного контента, просмотрите --> «Андроид-разработка»


---------------------
Автор: Дядя Бу
Источник: CSDN
Оригинал: https://blog.csdn.net/u011578734/article/details/110523825
Заявление об авторских правах: Это статья является оригинальной статьей автора, пожалуйста, прикрепите ссылку на сообщение в блоге для перепечатки!
Анализ контента Автор: CSDN, CNBLOG, запись в блоге, плагин для перепечатки одним щелчком мыши

Supongo que te gusta

Origin blog.csdn.net/xiaowang_lj/article/details/131893248
Recomendado
Clasificación