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

Если вам в проекте необходимо загружать картинки и/или отправлять 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, если задачи не долгие и не требуют кеширования. Вы же вольны выбирать всё, что вам угодно.

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

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

Если кто-то заметил лямбды в примерах кода, но не знает, что это, как и зачем — обратите внимание на этот проект.
Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 11

    +1
    groundy?
    –1
      0
      Я, к сожалению, не использовал. Тоже хотел бы услышать отзывы о ней.
        0
        очень простая и удобная для мелких задач либа, советую поглядеть.
      0
      Какое-то время использовал Volley, но вернулся к Robospice.
        +1
        Кроме Groundy еще Android Priority Job Queue внушал доверие. Но последнему коммиту год и теперь он внушает смешанные чувства. Вообще, такое обилие костылей вокруг асинхронных вызовов на андроид «какбэ намекает» — что-то пошло не так. Ходят слухи, что венценосная RxJava, последний тренд в тату салонах для айтишников, решает фатальный недостаток, но, что случается гораздно чаще, просто делает резюме круче и превращает все ваше приложение в один большой недостаток. Реактивно.
          0
          Android Priority Job Queue очень хороший продукт, сейчас он был форкнут и продолжает развиваться. Хотя там уже все почти есть, не хватает только отмены задач.
          0
          Советую обратить внимание на github.com/path/android-priority-jobqueue
            –1
            По моему какая то сумбурная статься получилась. Конечно AsyncTask не подходят для длительных операций, если Вы их запускаете и храните в Activity. Конечно Robospice подходит для длительных операций, если использует сервис для их выполнения. Никто не мешает запустить AsyncTask в сервисе. Никто не мешает запустить сервис в отдельном процессе. А о каких асинхронных запросах вообще речь? Если HTTP/REST, то тут только ленивый не написал своего решения :) Уже упоминался Volley, я тоже его порекомендую: очередь с приоритетами, кеширование, можно использовать для картинок, можно подсовывать любой HTTP-stack, от UrlConnection до OkHttp. Только не понятно тогда, почему Вас интересуют длительные запросы. Pdf-ку скачать?
              0
              1. Мне например это было не очевидно
              2. AsyncTask никто не мешает в сервисе запустить это да, но если нужно передать данные в активити, то придется писать ооочень много кода

            Only users with full accounts can post comments. Log in, please.