Есть некоторое приложение, которое по запросу пользователя загружает некоторые данные из сети и отображает их. Сетевые запросы в этом приложении выполняются в отдельном потоке средствами AsyncTask.
Ввиду того, что многие категорически советуют не использовать AsyncTask при работе с интернетом (а выносить сетевые запросы в сервис) и возник данный вопрос.
Чуть подробнее:
Суть приложения - отображение списка (текстовых) новостей из нескольких источников.
Как это реализовано сейчас:
Есть активити с Navigation Drawer, в котором отображается список сайтов, по клику на определенный пункт меню появляется фрагмент, содержащий RecyclerView, куда с помощью AsyncTask загружаются данные с выбранного сайта.
При прокрутке RecyclerView до определенного элемента запускается AsyncTask который подгружает в RecyclerView следующую порцию информации и так далее (эдакий Endless RecyclerView).
При выборе другого пункта меню, появляется другой фрагмент, но с таким же принципом работы (просто данные грузятся из другого источника).
При создании каждого из фрагментов выполняется setRetainInstance(true), то есть при изменении конфигурации устройства данные из AsyncTask благополучно вернутся в нужный фрагмент.
Процесс извлечения нужной информации с сайтов организован с помощью Jsoup.
Вопросы:
Чем плоха такая архитектура данного приложения? (в части использования AsyncTask и в общем).
Хорошим ли тоном для данной конкретной задачи является использование AsyncTask? Или же стоит перенести работу с сетью в сервис? (я понимаю, что не все типы сервисов работают не в главном потоке).
А если все же стоит перенести работу с сетью в сервис, то при необходимости загрузки данных запускать сервис, загружать данные, возвращать данные во фрагмент и завершать сервис? И так каждый раз?
Честно говоря, хоть и на каждом углу написано, что AsyncTask - это плохо, я не вижу явных причин для вынесения работы с сетью в сервис в данном конкретном приложении. Но раз многие говорят, значит я чего-то не понимаю. Объясните мне это, пожалуйста.
По сути, AsyncTask же предназначен для кратковременных задач, а у меня загружается очень небольшой объем данных (текст), и в итоге AsyncTask как раз отрабатывает за пару секунд.
А основное назначение сервиса - это, насколько я понял, выполнение длительных фоновых задач.
Еще раз повторюсь - я не утверждаю, что в данном случае лучшим решением будет использование AsyncTask, но и аргументов против его использования я не вижу.
А может есть какие-либо другие более правильные архитектурные решения для данной задачи?
Хоть интернет и читал (очень много читал), но буду рад как ссылкам, где описывается что-то подобное (может я пропустил), так и Вашим ответам по данной теме и Вашим мнениям по данному вопросу.
Честно говоря, хоть и на каждом углу написано, что AsyncTask - это плохо
Так говорят только те, кто не умеет их готовить. AsyncTask вполне нормальная практика, если вы умеете справляться с пограничными кейсами: поворот экрана, уничтожени контекста и т.п.
AsyncTask не рекомендуют использовать по большей степени потому что есть уже готовые нормальные библиотеки типо Volley, Retrofit и т.п.
Сервисы используются для тяжёлых задач или же для периодических задач.
Для задач асинхронной загрузки данных в отдельном потоке используется класс, наследующий AsyncTaskLoader<D> вместо Loader<D>. Класс AsyncTaskLoader<D> является абстрактным и работает как AsyncTask. На основе этого класса вы можете реализовать абстрактный метод loadInBackground().
Слушатель получает информацию от загрузчика. Для этого менеджер регистрирует слушатель OnLoadCompleteListener<D>, который прослушивает события. Когда загрузка закончилась, то вызывается метод onLoadFinished(Loader<D> loader, D result).
Чтобы загрузчик начал работать, его надо запустить. Запущенный загрузчик следит за данными, пока его не перезапустят или остановят.
Остановленный загрузчик продолжает мониторить изменения в данных, но не сообщает о них. При необходимости вы можете заново запустить или перезапустить остановленный загрузчик.
При перезапуске загрузчик не должен запускать новую загрузку данных и мониторить изменения. Его задача - освободить лишние данные. Это состояние редко используется, но в некоторых случаях оно нужно.
Ваша задача сводится к созданию собственного загрузчика, реализации метода loadInBackground() и переопределении методов onStartLoading(), onStopLoading(), onReset(), onCanceled(), deliverResult(D results).
Подробнее здесь.
Вся беда обычного AsyncTask заключается в повороте экрана, в основном.
В случае с AsyncTaskLoader по поводу поворота экрана за Вас уже позаботились. Этот класс замечательно вписывается под Вашу задачу, но вообще я бы просто посоветовал на собственном устройстве желательно с 2G\3G (медленным интернетом) подгружать новые данные и часто поворачивать экран, при этом мониторить память на устройстве. Если даже при медленном интернете утечек не будет и\или она будет, но скажем, размером с одну активити - можете оставить Ваш вариант.
Но нужно помнить одну важную строчку из GoF - любой код претерпевает изменения.
И если Вы собираетесь и дальше улучшать функционалом приложение, то в любом случае дойдете до точки, когда элементы списка будут загружать более тяжелую информацию(фотографии, местоположение и тд).
Поэтому смотрите на потенциал, насколько необходимо будет его поддерживать.
Сборка персонального компьютера от Artline: умный выбор для современных пользователей