О фоновых "задачах"

Не так давно я увидел, что AsyncTask объявлен устаревшим. Конечно, сейчас его ещё поддерживают, но потом... Поэтому возникает вопрос: какие альтернативы он имеет? Конечно, я прочитал их названия и посмотрел их реализацию, но на первый взгляд они не кажутся такими же простыми.

  1. Есть ли разница между отдельным потоком (а-ля Thread, HandlerThread) и выполнением в AsyncTask.doInBackground?

Очень часто я использовал AsyncTask для того, чтобы производить длительные операции (не как это рекомендовано). Например, 'анимация' фона приложения: запускал в самом начале задачу, и она каждые полторы секунды добавляла новое число и удаляла старое. Она выполнялась всё время работы приложения вот так:

@Override
protected String doInBackground(String... strings) {
    HandlerThread thread = new HandlerThread("Animation");
    thread.start();
    final Handler handler = new Handler(thread.getLooper());
    Runnable anim = new Runnable() {
        public void run() {
            //Создаём новый текстовый вид, выбираем случайно число, записываем его в вид.
            publishProgress(text);
            handler.postDelayed(this, 1500);
        };
    };
    handler.post(anim);
    return "OK";
};
// В onProgressUpdate добавляем вид в 'корневой' Layout.

Здесь я создаю новый поток. Но возможно ли сделать это в очередном новом потоке?

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

P.S. под альтернативами я понимаю: Executor, ThreadPoolExecutor, FutureTask.

P.P.S. по моему субъективному мнению, их намного сложнее использовать.


Ответы (1 шт):

Автор решения: Сергей Бувака

AsyncTask в лучшие для него времена являлся не самым лучшим инструментом. Да он просто в понимании, но у него много недостатокв:

  • Каждый раз нужно писать достаточно много кода для решения относительно простой задачи.

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

  • AsyncTask не поддерживает сохранение состояния прогресса и повторное использование результатов загрузки.

Threads это самая низкоуровневая абстракция для работы с потоками в Java. В Android в чистом виде их уже давно никто не использует, как впрочем и Executors, хотя со вторыми работать проще.

В Android вы можете использовать Handler-ы. Эти в свою очередь являются фреймворком андроида. Это самый низкоуровневый инструмент для работы с потоками в Android. И в целом он является предпочтительным (при условии, что вы не используете сторонние библиотеки). Он более сложен, но и дает в свою очередь больше контроля.

RXJava это сторонняя библиотека, котороая очень распространена. В ней есть огромное количество возможностей и удобная работа с потоками. И в целом она решает огромный пул проблем. НО, надо понимать несколько вещей:

  • При всем удобстве работы с многопоточностью, RX это не про потоки, а про асинхронность.

  • В нее очень высокий порог вхождения.

  • RX очень большая библиотека, и тянуть ее в проект только для того, чтоб сходить в рабочем потоке в базу/сеть не лучшая идея.

Корутины. Корутины это решение от JetBrains для работы с потоками в Котлине. Они просты в использовании, корутины можно запускать в огромный количествах в отличии от нативных потоков. Кот пишется как синхронный и потому его легко писать и читать. Хоть они и подключаются отдельной зависимостью это решение на уровне языка (Kotlin), а значит его можно считать нативным и уверенно пользоваться им. К тому же к корутинам уже в тесте есть библиотека Flow которая будет аналогом RX Java с теми же возможностями. Из минусов только то, что это все же свежее решение и она не зайдет в проекты с большим легаси. Ну или вам придется писать какие-то абстракции.

А вообще эта тема очень огромна и обширна и тут одним ответом StackOverflow не ограничишься.

→ Ссылка