What is loadermanager in android

Loader, LoaderManager

Метки: LoaderManager , Loader , LoaderManager.LoaderCallbacks , AsyncTaskLoader , CursorLoader

В старых версиях Android при работе с курсором использовались методы, которые теперь считаются устаревшими.

  • startManagingCursor(Cursor)
  • managedQuery(Uri, String, String, String, String)

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

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

Например, загрузим данные в список старым способом, используя контент-провайдер. Результат обрабатывается адаптером SimpleCursorAdapter и выводится на экран.

От этого кода следует отказаться по описанным выше причинам, чтобы не иметь проблем с производительностью.

Начиная с Android 3.0, появился другой механизм работы с курсором — загрузчик Loader и менеджер LoaderManager, которые также доступны в библиотеке совместимости для старых устройств.

Теперь все операции с курсорами происходят в асинхронном режиме. А данные кэшируются и при необходимости информация обновляется, если данные изменились.

LoaderManager

LoaderManager позволяет грамотно управлять загрузчиками, связанными с активностью или фрагментом. Каждая активность и каждый фрагмент имеет один экземпляр менеджера LoaderManager, который работает с загрузчиками через методы initLoader(), restartLoader(), destroyLoader(). Активность через данного менеджера может предупредить о своём уничтожении, чтобы LoaderManager в свою очередь закрыл загрузчики для экономии ресурсов.

Сам LoaderManager не знает, как данные загружаются в приложение. Он просто даёт указания загрузчику начать, остановить, обновить загрузку данных и другие команды.

LoaderManager работает с объектами Loader , где D является контейнером для загружаемых данных. При этом данные не обязательно должны быть курсором. Это могут быть и List, JSONArray и т.д. В одной активности может быть несколько загрузчиков, которые являются объектами.

Класс Loader является общим. Также доступны специализированные загрузчики AsyncTaskLoader и CursorLoader.

Работа с LoaderManager происходит через три метода обратного вызова интерфейса LoaderManager.LoaderCallbacks .

Интерфейс LoaderManager.LoaderCallbacks

Интерфейс LoaderManager.LoaderCallbacks определяет порядок взаимодействия с загрузчиком через методы:

onCreateLoader()

Метод onCreateLoader() возвращает новый загрузчик. LoaderManager вызывает метод при создании Loader.

При попытке доступа к загрузчику (например, посредством метода initLoader()), он проверяет, существует ли загрузчик, указанный с помощью идентификатора. Если он не существует, он вызывает метод onCreateLoader(). Именно здесь и создаётся новый загрузчик.

onLoadFinished()

Метод onLoadFinished вызывается автоматически, когда Loader завершает загрузку данных. Загрузчик следит за поступающими данными, а менеджер получает уведомление о завершении загрузки и передаёт результат данному методу.

Этот метод гарантировано вызывается до высвобождения последних данных, которые были предоставлены этому загрузчику. К этому моменту необходимо полностью перестать использовать старые данные (поскольку они скоро будут заменены). Однако этого не следует делать самостоятельно, поскольку данными владеет загрузчик и он позаботится об этом. Загрузчик высвободит данные, как только узнает, что приложение их больше не использует. Например, если данными является курсор из CursorLoader, не следует вызывать close() самостоятельно. Если курсор размещается в CursorAdapter, следует использовать метод swapCursor() с тем, чтобы старый Cursor не закрылся.

onLoadReset()

Метод onLoadReset() перезагружает данные в загрузчике.

Этот метод вызывается, когда состояние созданного ранее загрузчика сбрасывается, в результате чего его данные теряются. Этот обратный вызов позволяет узнать, когда данные вот-вот будут высвобождены, с тем чтобы можно было удалить свою ссылку на них.

Порядок работы менеджера загрузчиков во время создания активности.

Application.onCreate()
Activity.onCreate()
LoaderManager.LoaderCallbacks.onCreateLoader()
Activity.onStart()
Activity.onResume()
LoaderManager.LoaderCallbacks.onLoadFinished()

При изменении конфигурации (поворот и т.п.):

Application:config changed
Activity.onCreate
Activity.onStart
[No call to the onCreateLoader]
LoaderManager.LoaderCallbacks.onLoadFinished
[optionally if searchview has text in it]
SearchView.onQueryChangeText (Поиск по тексту, см. примеры ниже)
RestartLoader
LoaderManager.LoaderCallbacks.onCreateLoader
LoaderManager.LoaderCallbacks.onLoadFinished

При уничтожении активности:

Activity.onStop()
Activity.onDestroy()
LoaderManager.LoaderCallbacks.onLoaderReset() //Обратите внимание, что этот метод вызывается

Загрузчик (Loader)

Менеджер загрузчиков управляет загрузчиками. Загрузчик предназначен для загрузки данных из источника: диск, база данных, контент-провайдер, сеть или другой процесс. Загрузчик производит выборку данных без блокировки главного потока в отдельном потоке и доставляет результаты стороне, которая в них заинтересована, следя за изменениями данных и информирует о всех важных изменениях менеджеру через специальные слушатели.

Таким образом, активность или фрагмент не интересуются, как загружаются данные. Они доверили эту работу загрузчику.

Существуют три встроенных типа загрузчиков: Loader, AsyncTaskLoader и CursorLoader. Loader — базовый класс, который сам по себе не очень полезен. Он определяет API, используемый LoaderManager для взаимодействия со всеми загрузчиками.

AsyncTaskLoader

Для задач асинхронной загрузки данных в отдельном потоке используется класс, наследующий AsyncTaskLoader вместо Loader . Класс AsyncTaskLoader является абстрактным и работает как AsyncTask. На основе этого класса вы можете реализовать абстрактный метод loadInBackground().

Слушатель получает информацию от загрузчика. Для этого менеджер регистрирует слушатель OnLoadCompleteListener , который прослушивает события. Когда загрузка закончилась, то вызывается метод onLoadFinished(Loader loader, D result).

Чтобы загрузчик начал работать, его надо запустить. Запущенный загрузчик следит за данными, пока его не перезапустят или остановят.

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

При перезапуске загрузчик не должен запускать новую загрузку данных и мониторить изменения. Его задача — освободить лишние данные. Это состояние редко используется, но в некоторых случаях оно нужно.

Ваша задача сводится к созданию собственного загрузчика, реализации метода loadInBackground() и переопределении методов onStartLoading(), onStopLoading(), onReset(), onCanceled(), deliverResult(D results).

Небольшой пример для демонстрации.

Создадим кнопку и текстовую метку на экране.

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

Переменная mWord будет хранить базовую строку, на основе которой будет создаваться случайная строка. Этот параметр передается при создании загрузчика в конструктор с использованием объекта Bundle. Константа RANDOM_STRING_LENGTH задает максимальную длину новой случайной строки.

Наследуясь от AsyncTaskLoader, мы переопределяем несколько методов:

  • loadInBackground() — метод, в котором собственно и должна быть создана вся работа по загрузке данных
  • onStartLoading() — срабатывает при запуске загрузчика (но это еще не означает загрузку данных)
  • onStopLoading() — срабатывает при остановке загрузчика
  • deliverResult() — получает и возвращает итоговый результат работы загрузчика
  • forceLoad() — «принудительная» загрузка новых данных
Читайте также:  Как установить виджет часы android

Для получения данных в методе loadInBackground() мы вызываем вспомогательный метод generateString(), который генерит случайную строку.

Класс активности реализует интерфейс LoaderManager.LoaderCallbacks с его методами, позволяющий нам «участвовать» в жизненном цикле загрузчика и взаимодействовать с LoaderManager.

Метод onCreateLoader() — вызывается при инициализации загрузчика. Если загрузчик с таким идентификатором уже был создан, то метод не вызовется. Внутри мы определяем, какой идентификатор нам был передан, чтобы создать нужный загрузчик. Если загрузчик только один, то условие можно убрать.

Метод onLoadFinished() вызывается по окончанию загрузки. В метод приходят загруженные данные, а также объект загрузчика. Полученную строку мы выводим в текстовой метке.

Метод onLoaderReset() вызывается при «сбросе» состояния загрузчика. Здесь данные обнуляются, и нам нужно удалить все имеющиеся ссылки на них.

Щелчок кнопки выполняет роль триггера для запуска новой загрузки данных. Мы используем метод onContentChanged(), чтобы сигнализировать загрузчику об изменении данных.

Как происходит первый запуск загрузчика? Мы это делаем в методе onCreate(), инициализируя загрузчик. При инициализации мы передаем в параметрах идентификатор загрузчика, Bundle — объект, содержащий передаваемые аргументы (мы передаем базовую строку) и указатель на callback-объект (в нашем случае — это сама активность).

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

CursorLoader

Класс CursorLoader является наследником класса Loader и работает с курсорами в асинхронном режиме. CursorLoader расширяет AsyncTaskLoader для загрузки Cursor из ContentProvider через ContentResolver.

Источник

Полный список

— изучаем Loader и AsyncTaskLoader

Лоадеры появились в третьей версии Android. Предназначены для выполнения асинхронных операций и привязаны к некоторым lifecycle-методам Activity или Fragment-ов.

Я когда-то пытался уже эту тему осилить, но с ходу не получилось: не особо понял смысл и механизмы. Но создатели Android не дремлют. Они некоторые методы по работе с БД объявили устаревшими и очень рекомендуют использовать CursorLoader. Из-за этого мне теперь надо Урок 52 переделывать. И я решил, что сначала имеет смысл все-таки разобраться и осветить тему Loader-ов, а потом уже обновлю Урок 52.

Итак, имеем два класса.

LoaderManager – встроен в Activity и Fragment. Как и следует из названия он управляет объектами Loader. Он их создает, хранит, уничтожает и стартует/останавливает. Для взаимодействия с ним используется колбэк интерфейс LoaderCallbacks.

Loader – объект, который должен уметь асинхронно выполнять какую-либо задачу.

Напишем приложение, в котором используем лоадер, и посмотрим его поведение на примерах. Лоадер будет просто определять текущее время, но делать это он будет асинхронно и с учетом формата.

Project name: P1351_Loader
Build Target: Android 4.0
Application name: Loader
Package name: ru.startandroid.develop.p1351loader
Create Activity: MainActivity

В strings.xml добавим строки:

Текст для отображения времени, выбор формата: короткий и длинный, кнопка получения времени и кнопка для работы с Observer-ом, который мы попробуем прикрутить к лоадеру.

Создадим класс лоадера. Причем, не в MainActivity, а отдельно, чтобы было нагляднее. Вообще, можно и в MainActivity создавать, но при этом есть ограничение: он должен быть static. Иначе LoaderManager ругнется: «Object returned from onCreateLoader must not be a non-static inner member class«.

Лоадер будет асинхронно получать время. При этом будем эмулировать паузой долгое выполнение, как будто он на какой-нить сервер ходит и оттуда данные получает. Я поставил паузу в 10 сек, но можно поставить и меньше, чтобы не ждать долго выполнение примеров. Выводить время он будет уметь в двух форматах – коротком и длинном, это соответственно константы TIME_FORMAT_SHORT и TIME_FORMAT_LONG.

Наш класс расширяет класс Loader. Loader является параметризированным классом, поэтому нам в скобках <> необходимо указать класс-тип, который указывает, что будет возвращать лоадер после своей работы. Наш лоадер будет возвращать строку с временем, поэтому я указываю здесь String.

В конструкторе читаем из Bundle данные о формате времени. Если ничего не пришло, то будем использовать короткий формат.

Далее идут 5 стандартных методов лоадера.

onStartLoading – вызывается при старте (onStart) Activity или фрагмента, к которому будет привязан Loader.

onStopLoading – вызывается при остановке (onStop) Activity или фрагмента, к которому будет привязан Loader.

Сразу надо определиться с формулировкой состояний. Будем считать что лоадер перешел в состояние «стартован» после метода onStartLoading и в состояние «остановлен» после метода onStopLoading. Это необходимо, т.к. поведение лоадера зависит от состояния и нам в дальнейшем нужно будет эти состояния как-то словесно идентифицировать.

Надо понимать, что два этих метода автоматически не означают, что лоадер начал или закончил работу. Это просто переход в состояние стартован и остановлен. А будет он в это время работать или нет, определять вам.

onForceLoad — в этом методе кодим работу лоадера. Запускаем здесь GetTimeTask, который будет нам время получать асинхронно. Ниже разберем подробно, что он делает.

onAbandon – метод означающий, что лоадер становится неактивным. Далее на примере будет видно, что это означает.

onReset – означает уничтожение лоадера, вызывается при закрытии (onDestroy) Activity или фрагмента, к которому будет привязан Loader. Не вызывается, если onDestroy был вызван, например при смене ориентации.

Далее рассмотрим примеры и увидим, когда и какие методы вызываются.

Метод getResultFromTask – это наш метод. GetTimeTask, по окончании своей работы, вызовет этот метод и передаст нам результаты своей работы. А мы уже вызываем в нем стандартный метод лоадера – deliverResult, который оповещает слушателя, подключенного к лоадеру, что работа окончена и передает ему данные.

GetTimeTask – это AsyncTask, который берет на вход формат даты и через определенную паузу возвращает (с помощью getResultFromTask) в лоадер текущее время в этом формате.

Читайте также:  Отличия android от linux

В onCreate мы получаем объект LoaderManager с помощью метода getLoaderManager и вызываем его метод )» target=»_blank» rel=»noopener noreferrer»>initLoader, который создаст и вернет нам Loader. В качестве параметров метода initLoader указываем:
— ID лоадера, это необходимо, т.к. мы запросто можем использовать сразу несколько разных лоадеров, и LoaderManager да и мы сами должны их как-то различать
— объект Bunlde. В него вы помещаете данные, которые хотите использовать при создании лоадера
— объект, реализующий колбэк-интерфейс LoaderCallbacks. Он будет использоваться для взаимодействия с лоадером.

Итак, посмотрим, что мы передали в initLoader. В качестве ID используем константу LOADER_TIME_ID. В Bundle помещаем формат времени, который хотим получить. Для определения формата используем свой метод getTimeFormat(), его обсудим ниже. И третьим параметром метода идет MainActivity, которое реализует интерфейс LoaderCallbacks. На всякий случай поясню, что можно было и создать отдельный объект для этого колбэка, а не использовать Activity. Кому как удобнее.

Метод initLoader возвращает созданный лоадер, но я его никуда не сохраняю, т.к. мне это здесь не нужно.

Интерфейс LoaderCallbacks требует реализации трех методов:

onCreateLoader – вызывается, когда требуется создать новый лоадер, например, в тот момент, когда мы выше вызываем метод initLoader. На вход получает ID требуемого лоадера и Bundle с данными. Т.е. те самые объекты, что мы передавали в initLoader.

, D)» target=»_blank» rel=»noopener noreferrer»>onLoadFinished – срабатывает, когда лоадер закончил работу и вернул результат. На вход приходит сам лоадер и результат его работы.

)» target=»_blank» rel=»noopener noreferrer»>onLoaderReset – срабатывает, когда LoaderManager собрался уничтожать лоадер. На вход получает лоадер.

Далее на примерах увидим порядок вызовов этих трех методов.

Метод getTimeClick – обработчик кнопки Get time. В нем мы определяем: в каком формате требуется получить время. Далее проверяем, если последний созданный лоадер был создан с учетом этого же формата, то просто получаем лоадер методом getLoader по ID. Если же формат другой, то нам нужен новый лоадер. Для этого используется метод )» target=»_blank» rel=»noopener noreferrer»>restartLoader. Он принимает на вход те же параметры, что и initLoader, и создает новый лоадер. Далее у полученного лоадера вызываем метод forceLoad, тем самым запуская работу.

Как видим, у LoaderManager есть аж три метода для получения лоадера: getLoader, initLoader и restartLoader. Давайте сразу проговорим их отличия.

getLoader – просто получение лоадера с указанным ID. Если лоадер с таким ID еще не был создан, то метод вернет null.

initLoader – создание лоадера если он не существовал. Если лоадер существовал, то метод его и вернет, только заменит колбэк-объект, который вы передаете в метод. А если лоадер не просто существовал, но и уже успел отработать, то в метод onLoadFinished отправится его последний результат.

restartLoader – создание нового лоадера в любом случае. Чуть позже мы рассмотрим на примерах, что происходит если при работающем лоадере создать новый.

Надеюсь, что теперь стала понятнее логика метода getTimeClick.

Методе getTimeFormat просто возвращает формат времени в зависимости от выбранного на экране формата.

Метод observerClick пока оставим пустым. Позже заполним.

Почти во все методы я добавил логи, чтобы видеть порядок выполнения методов. А хэш-коды лоадеров позволят нам видеть для какого лоадера эти методы выполняются.

Все сохраняем, запускаем приложение.

На экране пока не отображено время, т.к. лоадер пока только перешел в состояние «стартован», но работать не начинал.

1091125312 create TimeLoader
onCreateLoader: 1091125312
1091125312 onStartLoading

Видим, что метод initLoader в onCreate вызвал метод onCreateLoader, в котором был вызван конструктор TimeLoader. А метод onStartLoading сработал при старте Activity.

Свернем приложение, нажав Home.

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

Закроем приложение кнопкой Back

1091125312 onStopLoading
1091125312 onReset

Видно, что Activity в своих lifecycle-методах вызывает соответствующие методы лоадера: при старте – onStartLoading, при остановке — onStopLoading, а при закрытии – onReset.

Заметим, что не был вызван onLoaderReset. Он вызывается только в случае, когда хоть раз были получены данные. Далее в примерах увидим это.

Посмотрим лоадер в работе. Снова запустим приложение, оставим формат времени Short и жмем Get time. Ждем 10 сек и видим на экране результат.

Смотрим логи работы:

1091254864 onForceLoad
1091254864 doInBackground
1091254864 onPostExecute 10:57:15 после полудня
onLoadFinished for loader 1091254864, result = 10:57:15 после полудня

В onForceLoad запустился и отработал AsyncTask и колбэк лоадера получил результат в onLoadFinished.

Попробуем еще раз. Но теперь проверим, что будет, если свернуть приложение при работе лоадера.

Нажмем Get time и сразу же свернем приложение кнопкой Home.

1091254864 onForceLoad
1091254864 doInBackground
1091254864 onStopLoading
1091254864 onPostExecute 11:00:26 после полудня

Видим, что уже после onStopLoading AsyncTask вернул результат, но onLoadFinished уже не отработал, т.к. лоадер остановлен.

Теперь проверим, что будет если при работающем лоадере мы закроем приложение.

Откроем приложение, нажмем Get time и закроем приложение кнопкой Back.

1091254864 onForceLoad
1091254864 doInBackground
1091254864 onStopLoading
onLoaderReset for loader 1091254864
1091254864 onReset
1091254864 onPostExecute 11:03:00 после полудня

Видим, что после onStopLoading лоадер был уничтожен. В этот раз, кстати сработал метод onLoaderReset, т.к. этот лоадер ранее уже получал данные. AsyncTask честно отработал и вернул результат, но это уже никому не интересно, т.к. лоадер уничтожен.

Теперь проверим работу метода restartLoader.

Откроем приложение, нажмем Get time. Дождемся пока лоадер отработает и покажет время, а затем переключим формат на Long и еще раз жмем Get time и дождемся пока отработает новый лоадер.

1091662504 create TimeLoader
onCreateLoader: 1091662504
1091662504 onStartLoading
1091662504 onForceLoad
1091662504 doInBackground
1091662504 onPostExecute 11:08:42 после полудня
onLoadFinished for loader1091662504, result = 11:08:42 после полудня
1091662504 onAbandon
1091700592 create TimeLoader
onCreateLoader: 1091700592
1091700592 onStartLoading
1091700592 onForceLoad
1091700592 doInBackground
1091700592 onPostExecute 2013.11.04 н.э. at 23:08:56
onLoadFinished for loader1091700592, result = 2013.11.04 н.э. at 23:08:56
1091662504 onReset

По хэш-кодам видно, что у нас в работе было два лоадера: первый – 1091662504, второй — 1091700592 (у вас могут быть другие хэш-коды).

Читайте также:  Как починить андроида people playground

При создании второго лоадера, у первого был вызван метод onAbandon, означающий, что первый лоадер становится устаревшим и более не является текущим. Т.е. метод getLoader уже его не вернет. Теперь текущий лоадер – второй. Далее идет стандартный набор методов работы второго лоадера и когда он успешно отрабатывает и возвращает результат, вызывается метод onReset первого лоадера. Т.е. после успешной работы второго лоадера первый лоадер уничтожается.

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

Оставляем формат Long, нажмем Get time, затем сразу же переключим на Short и снова нажмем Get time и дождемся результат. Смотрим логи.

1091700592 onForceLoad
1091700592 doInBackground
1091700592 onAbandon
1091713440 create TimeLoader
onCreateLoader: 1091713440
1091713440 onStartLoading
1091713440 onForceLoad
1091713440 doInBackground
1091700592 onPostExecute 2013.11.04 н.э. at 23:16:39
1091713440 onPostExecute 11:16:41 после полудня
onLoadFinished for loader 1091713440, result = 11:16:41 после полудня
1091700592 onReset

Теперь первый лоадер – 1091700592, второй – 1091713440. Схема в целом та же: первый лоадер переводится в разряд старых (onAbandon) при создании второго. Но результат в onLoadFinished считается только у второго, т.к. он является текущим, а результат старого лоадера будет проигнорен.

Теперь попробуйте повернуть девайс, чтобы сменилась ориентация экрана. Видим, что последний результат снова на экране. Смотрим лог:

onLoadFinished for loader 1091713440, result = 11:16:41 после полудня

При повороте экрана у нас сработал initLoader в onCreate и вызвал onLoadFinished с последним результатом текущего лоадера. Соответственно, если вы запустите в работу новый лоадер и пока он работает повернете экран, то вам ничего не вернется, т.к. у этого лоадера еще нет результата.

ContentObserver

Лоадеры умеют работать с объектами ContentObserver. Это такой объект, который сообщит вам, что интересующие вас данные изменились и имеет смысл их снова прочесть.

У лоадера есть своя реализация этого класса: ForceLoadContentObserver. Когда он получает уведомление о том, что данные были изменены, он действует в зависимости от состояния лоадера:
— если лоадер в стартованном состоянии (onStartLoading), то вызывается метод forceLoad, который должен эти новые данные считать
— если же лоадер остановлен (onStopLoading), то ставится метка о том, что данные были изменены и лоадер при старте может эту метку прочесть и запустить все тот же forceLoad для чтения данных

Добавим в наше приложение работу с ContentObserver. Для этого в MainActivity реализуем обработчик кнопки Observer:

Создаем экземпляр ForceLoadContentObserver и эмулируем ситуацию: он через 5 сек сообщит нам о том, что данные изменились.

А в лоадере перепишем onStartLoading:

Здесь мы читаем (и одновременно сбрасываем) метку методом takeContentChanged. Если метка говорит, что данные были изменены (true), то запускаем работу.

Все сохраняем, запускаем приложение. Жмем Observer, ждем результат и смотрим логи:

1091644064 create TimeLoader
onCreateLoader: 1091644064
1091644064 onStartLoading
observerClick
1091644064 onForceLoad
1091644064 doInBackground
1091644064 onPostExecute 10:31:26 после полудня
onLoadFinished for loader 1091644064, result = 10:31:26 после полудня

Видим, что Observer через 5 сек после нажатия кнопки запустил метод forceLoad. Дальше все как обычно.

Теперь еще раз нажмем Observer и сразу же свернем приложение кнопкой Home.

Здесь Observer также сработал, но метод forceLoad не запускал, т.к. лоадер был остановлен. В этом случае поставилась метка о том, что данные изменены. И сейчас мы эту метку считаем.

Откроем приложение из списка последних

1091644064 onStartLoading
1091644064 onForceLoad
1091644064 doInBackground
1091644064 onPostExecute 10:32:42 после полудня
onLoadFinished for loader 1091644064, result = 10:32:42 после полудня

Приложение восстановилось, при этом сработал onStartLoading, в котором мы прочли метку, поняли, что данные изменились, и стартовали onForceLoad.

Напоследок еще пара слов.

Важное замечание! Все рассмотренные выше примеры работают при условии, что initLoader вызывается в onCreate. Если есть интерес, попробуйте переделать логику приложения убрав initLoader из onCreate и лоадер начнет себя вести по-другому, изменится его связка с lifecycle методами.

Лоадер можно убить вручную, использовав метод destroyLoader.

Все вышесказанное должно работать с фрагментами (у них есть свой метод getLoaderManager) и с android.support.v4.app.FragmentActivity (метод getSupportLoaderManager).

AsyncTaskLoader

Это лоадер, который выполнит свою работу асинхронно и вернет вам результат. Класс TimeLoader, который мы сделали, в принципе является упрощенной версией AsyncTaskLoader, т.к. он свою работу тоже в AsyncTask выполняет. Но чтобы самим каждый раз не возиться с AsyncTask, существует AsyncTaskLoader.

Создадим класс TimeAsyncLoader.java:

Полностью тот же функционал, что и в TimeLoader, только теперь рабочий код мы просто помещаем в метод loadInBackground. Я в этом классе уже не буду снова переопределять и логировать все его основные методы.

Чтобы использовать этот лоадер в MainActivity, потребуются минимальные изменения. Надо просто в onCreateLoader указать, что по LOADER_TIME_ID необходимо создавать не TimeLoader, а TimeAsyncLoader:

Запускайте пример, внешне он будет работать точно также, но использовать теперь будет не TimeLoader, а TimeAsyncLoader. Ну и логов поменьше будет.

У класса AsyncTaskLoader есть метод отмены: cancelLoad. Отмененный лоадер по окончании работы вызовет уже не onLoadFinished, а onCanceled в AsyncTaskLoader.

Есть еще метод setUpdateThrottle, который позволит поставить задержку между двумя последовательными вызовами одного лоадера. Т.е. вы, например, поставили эту задержку в 10 000 мсек. Далее запускаете лоадер, он отрабатывает. И вы сразу пытаетесь запустить его еще раз. Но он не запустится. Он отсчитает 10 сек после окончания работы последнего запуска, а потом уже снова начнет работу.

На следующем уроке:

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Оцените статью