Как стать автором
Обновить

Сравнение библиотек для выполнения асинхронных запросов

Время на прочтение3 мин
Количество просмотров17K
Если вам в проекте необходимо загружать картинки и/или отправлять http-запросы, выполнять любую другую долгую операцию, которая может заблокировать UI поток, то как ни крути придется использовать решение для выполнения асинхронных запросов.

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

image

Самое тривиально решение AsyncTask


Плюсы:
1. Простой для понимания.
2. Решение из коробки.

Минусы:
1. Memory leak при перевороте экрана — старая activity не уничтожиться пока задача не выполниться, и результат придет в старую activity, и, скорее всего, вы словите exception.
2. Нет обработки ошибок.
3. Долгие операции будут прерваны как только система решит уничтожить ваше приложение (если вы его свернули например).

Пример кода:

requestDataTask = new AsyncTask<Void, Void, JSONObject>() {
            @Override
            protected JSONObject doInBackground(Void... params) {
                //Для обработки ошибок обычно заводят поля Exception. (не лучшее решение)
                final String requestResult = apiService.getData();
                final JSONObject json = JsonUtils.parse(requestResult);
                lruCache.cacheJson(json);
                return json;
            }
        };


Более современное решение — Loaders


Тоже самое, что и AsyncTask, за исключением одной вещи: при перевороте экрана можно результат получить в новой activity. Но 2-я и 3-я проблемы все равно присутствуют. И хотя Google рекомендует использовать loaders, не рекомендую этого делать. Вам придется писать много boilerplate code.

Пример можно посмотреть здесь, либо можно просто поверить мне и не использовать Loaders. Код не копирую сюда, так как уж очень многословные эти лоадеры.

А теперь самое лучшее решение на мой взгляд — Robospice


Плюсы:
1. Robospice выполняет все операции в service. Это значит, что если activity уничтожится, то задача все равно будет продолжать выполняться. Лучшее решение для долгих задач.
2. Есть методы для обработки ошибок.
3. Кеширование запросов, интеграция с Retrofit.

Но не все так радужно… Есть и минусы:
1. Нет метода для проверки исполняется задача или нет, а это очень важная вещь для меня. На github есть пул реквест с решением этой проблемы — #383. Кому надо — используйте этот форк.
2. Не самый удобный api в мире, но сойдёт.

Пример кода:

        spiceManager.execute(new SpiceRequest<String>(String.class) {
                                 @Override
                                 public String loadDataFromNetwork() throws Exception {
                                     Thread.sleep(1000);// поддерживается обработка ошибок
                                     return "It works!!!!";
                                 }
                             }, "key", DurationInMillis.ALWAYS_RETURNED,
                new RequestListener<String>() {
                    @Override
                    public void onRequestFailure(SpiceException spiceException) {

                    }

                    @Override
                    public void onRequestSuccess(String s) {

                    }
                });   


Достойное внимания решение — RxJava


Хорошое решение с кучей разных фич, подробнее можно прочитать на Хабре в публикации «Реактивное программирование под Android».
Вкратце от меня: есть обработка ошибок, поддержка жизненного цикла activity/fragment. Но не подходит для долгих операций (в отличие от Robospice), плюс лично мне было тяжело с ней разобраться, да и до сих пор кажется, что я не понимаю всего замысла.

Мой собственный велосипед — Slige Task


Плюсы:
1. Простой для понимания т.к. основан на AsyncTask.
2. Есть обработка ошибок.
3. Поддержка жизненного цикла activity.
4. Api немного поудобней.
5. Легко проверить, исполняется задача или нет.

Минусы:
1. Скудный функционал в отличии от RxJava.
2. Не подходит для долгих задач (см. Robospice).

Пример кода:

new SligeTask<String,Integer,String>((notifier, strings) -> {
            try {
                Thread.sleep(1000);
                return "executed successfully!!!";
            } catch (InterruptedException e) {
                notifier.publishError(e); //сообщит об ошибке в ErrorListener
                return null;
            }
        },LOADER_ID)
                .setPreExecuteListener(() -> setLoading(true))
                .setResultListener(this)
                .setErrorListener(this)
                .setCancelListener(this)
                .setDefaultCallbackLimiter(this) //Предотвратит выполнение коллбеков, если activity умрёт
                .execute();


Заключение


В заключение хотелось бы подвести итог. Лично я буду использовать в своих проектах форк Robospice и SligeTask, если задачи не долгие и не требуют кеширования. Вы же вольны выбирать всё, что вам угодно.

Да, библиотеки рассмотрены, конечно, не все (их очень много). Я рассмотрел самые популярные решения. Здесь вы можете найти кучу других.

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

Если кто-то заметил лямбды в примерах кода, но не знает, что это, как и зачем — обратите внимание на этот проект.
Теги:
Хабы:
Всего голосов 14: ↑11 и ↓3+8
Комментарии11

Публикации

Истории

Работа

iOS разработчик
27 вакансий
Swift разработчик
33 вакансии

Ближайшие события

One day offer от ВСК
Дата16 – 17 мая
Время09:00 – 18:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн
Антиконференция X5 Future Night
Дата30 мая
Время11:00 – 23:00
Место
Онлайн
Конференция «IT IS CONF 2024»
Дата20 июня
Время09:00 – 19:00
Место
Екатеринбург
Summer Merge
Дата28 – 30 июня
Время11:00
Место
Ульяновская область