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() — «принудительная» загрузка новых данных
Для получения данных в методе loadInBackground() мы вызываем вспомогательный метод generateString(), который генерит случайную строку.
Класс активности реализует интерфейс LoaderManager.LoaderCallbacks с его методами, позволяющий нам «участвовать» в жизненном цикле загрузчика и взаимодействовать с LoaderManager.
Метод onCreateLoader() — вызывается при инициализации загрузчика. Если загрузчик с таким идентификатором уже был создан, то метод не вызовется. Внутри мы определяем, какой идентификатор нам был передан, чтобы создать нужный загрузчик. Если загрузчик только один, то условие можно убрать.
Метод onLoadFinished() вызывается по окончанию загрузки. В метод приходят загруженные данные, а также объект загрузчика. Полученную строку мы выводим в текстовой метке.
Метод onLoaderReset() вызывается при «сбросе» состояния загрузчика. Здесь данные обнуляются, и нам нужно удалить все имеющиеся ссылки на них.
Щелчок кнопки выполняет роль триггера для запуска новой загрузки данных. Мы используем метод onContentChanged(), чтобы сигнализировать загрузчику об изменении данных.
Как происходит первый запуск загрузчика? Мы это делаем в методе onCreate(), инициализируя загрузчик. При инициализации мы передаем в параметрах идентификатор загрузчика, Bundle — объект, содержащий передаваемые аргументы (мы передаем базовую строку) и указатель на callback-объект (в нашем случае — это сама активность).
Ну теперь запускаем приложение и смотрим логи. При нажатии на кнопку текст обновляется, но в логах мы уже не видим повторного создания загрузчика.
CursorLoader
Класс CursorLoader является наследником класса Loader и работает с курсорами в асинхронном режиме. CursorLoader расширяет AsyncTaskLoader для загрузки Cursor из ContentProvider через ContentResolver.
Источник
ziginsider
Краткое описание. Создание. Использование.
Глобальная концепция: разработаны для работы с данными: загрузки (сохранения) данных (создание отдельного потока загрузки, загрузка, обработка ошибок, оповещение о состоянии загрузки). Нас интересует (в данный момент) одно частное применение лоадеров, а именно использование при пересоздании Activity (при изменении конфигурации) для сохранения состояния Activity
Лоадер – это компонент Android, который через класс LoaderManager связан с жизненным циклом Activity и Fragment. Это позволяет использовать их без опасения, что данные будут утрачены при закрытии приложения или результат вернется не в тот коллбэк. Разберем простейший пример (который хоть и простейший, но требует немало кода, это один из недостатков лоадеров). Создаем класс лоадера (для простоты он не будет грузить данные с сервера, а лишь имитировать загрузку):
В методе loadInBackground() — мы должны загрузить данные Integer — в данном примере это контейнер для данных (int), которые загружает наш лоадер.
В отличие от AsyncTask-а лоадер не нужно запускать вручную, это делается неявным образом через класс LoaderManager. У этого класса есть два метода с одинаковой сигнатурой:
- int id — идентификатор лоадера для различения их между собой;
- Bundle args — класс Bundle, с помощью которого передаем аргументы для создания лоадера;
- LoaderManager.LoaderCallbacks callback — Callback для создания лоадера и получения от него результата работы:
- onCreateLoader(int id, Bundle args) — необходимо вернуть нужный лоадер в зависимости от id, используя параметры из Bundle. Вызывается автоматически, при создании лоадера;
- onLoadFinished(Loader loader, D data) — в параметре D мы получим результат работы лоадера. Вызывается после того, как лоадер загрузит даннные. Для определения этого момента менеджер регистрирует слушатель OnLoadCompleteListener , который прослушивает события;
- onLoaderReset(Loader loader) — очищаем все данные, чвязанные с данным лоадером.
Создадим экземпляр LoaderCallback для нашего StubLoader’a:
И теперь запускаем лоадер:
Результат: через две секунды после запуска Activity покажется Toast. Теперь, если мы изменим конфигурацию Activity, например, перевернём устройство, то работа лоадера должна начаться заново и Toast должен показаться через 2 секунды. Но он показывается мнгновенно! В чём магия?
Лоадер запускается в методе initLoader класса LoaderManager. Лоадер создается при первом запуске Activity, но при последующих запусках он не пересоздаётся. Вместо этого LoaderManager заменяет экземпляр LoaderCallbacks на новый переданный, и если данные загрузились, они передаются в onLoadFinished.
Таким образом нам не нужно беспокоиться об обновлении данных и создании нового лоадера, но если данные необходимо перезагрузить, можно выполнить restartLoader.
Жизненный цикл лоадера
Порядок работы менеджера загрузчиков (LoaderManager) во время создания активности:
- Application.onCreate()
- Activity.onCreate()
- LoaderManager.LoaderCallbacks.onCreateLoader()
- Activity.onStart()
- Activity.onResume()
- LoaderManager.LoaderCallbacks.onLoadFinished()
При изменении конфигурации (поворот и т.п.):
Источник
Русские Блоги
Android Loader
Эта статья от: http://developer.android.com/guide/components/loaders.html#summary
Loaders
В Android 3.0 появился Loader для асинхронной загрузки данных, а загрузчики упрощают асинхронную загрузку данных в Activity и Fragment. Погрузчик имеет следующие характеристики:
1. они доступны для каждого действия и фрагмента .// Может использоваться в деятельности и фрагменте
2. обеспечивают асинхронную загрузку данных. // обеспечивают асинхронную загрузку данных
3. они контролируют источник своих данных и предоставляют новые результаты при изменении содержимого .// автоматически отслеживают изменения исходных данных и уведомляют данные и обновляют результаты данных
4. Они автоматически воссоединяются с курсором последнего загрузчика при воссоздании после изменения конфигурации. Таким образом, им не нужно повторно запрашивать свои данные. // Автоматически переподключаться к курсору последнего загрузчика при воссоздании после изменения конфигурации. Необходимо запрашивать данные повторно
Loader API Summary
В приложении есть несколько классов и интерфейсов, связанных с использованием загрузчика.
An abstract class associated with an Activity or Fragment for managing one or more Loader instances. This helps an application manage longer-running operations in conjunction with theActivity or Fragment lifecycle; the most common use of this is with a CursorLoader, however applications are free to write their own loaders for loading other types of data.
There is only one LoaderManager per activity or fragment. But aLoaderManager can have multiple loaders.
A callback interface for a client to interact with the LoaderManager. For example, you use the onCreateLoader() callback method to create a new loader.
An abstract class that performs asynchronous loading of data. This is the base class for a loader. You would typically useCursorLoader, but you can implement your own subclass. While loaders are active they should monitor the source of their data and deliver new results when the contents change.
Abstract loader that provides an AsyncTask to do the work.
A subclass of AsyncTaskLoader that queries theContentResolver and returns a Cursor. This class implements the Loader protocol in a standard way for querying cursors, building on AsyncTaskLoader to perform the cursor query on a background thread so that it does not block the application’s UI. Using this loader is the best way to asynchronously load data from aContentProvider, instead of performing a managed query through the fragment or activity’s APIs.
Указанные выше классы и интерфейсы являются необходимыми компонентами для реализации загрузчика, но вам не нужно реализовывать все вышеупомянутые классы и интерфейсы. Но для того, чтобы иметь возможность инициализировать Loader, вы должны содержать ссылку на LoaderManager. Вы также должны предоставить класс реализации Loader, такой как CursorLoader. Следующая часть расскажет вам, как использовать эти классы и интерфейсы для реализации загрузчика в вашем приложении.
Using Loaders in an application
В этом разделе описывается, как использовать Loader в приложении для Android. Типичное приложение, которое использует загрузчик, включает в себя:
1. Деятельность или фрагмент
2. Экземпляр LoaderManager
3. CursorLoader, класс реализации Loader, предоставляемый системой по умолчанию, используется для загрузки данных через ContentProvider. Конечно, вы также можете реализовать свой собственный загрузчик или AsyncTaskLoader для загрузки данных из других источников данных
4. Способ отображения данных загрузчика, например SimpleCursorAdapter
5. Источник данных. Например, при использовании источника данных ContentProvider из CursorLoader
Starting a Loader
LoaderManager управляет одним или несколькими экземплярами Loader в операции или фрагменте. В каждом действии или фрагменте может быть только один LoaderManager.
Обычно загрузчик инициализируется в методе onCreate () действия или в методе onActivityCreated () фрагмента. Следующим образом:
Метод initLoader получает следующие параметры:
1. Уникальный идентификатор загрузчика. В приведенном выше примере идентификатор равен 0
2. Необязательные параметры, которые предоставляются загрузчику для создания экземпляра загрузчика при создании загрузчика (ноль в приведенном выше примере)
3. Класс реализации LoaderManager.LoaderCallbacks. LoaderManager вызывает этот класс обратного вызова для сообщения о событиях Loader. В приведенном выше примере сам класс реализует интерфейс, поэтому он передает собственную ссылку: this.
Вызов initLoader () гарантирует, что загрузчик инициализирован и активен. Есть два результата:
1. Если вы укажете существующий идентификатор загрузчика, загрузчик, созданный в последний раз, будет использован повторно.
2. Если указанный идентификатор загрузчика не существует, метод initloader () вызовет метод обратного вызова onCreateLoader () объекта LoaderManager.LoaderCallbacks. В этом методе вы реализуете и возвращаете новый Loader. Подробнее об этом см. Раздел onCreateLoader.
Независимо от вышеупомянутых двух ситуаций, реализация LoaderManager.LoaderCallbacks связана с Loader и будет вызываться при изменении состояния Loader. Если загрузчик уже находится в начальном состоянии, загрузчик уже существует и его данные генерируются, система немедленно вызывает onLoadFinished () (во время initLoader ()). Поэтому вы должны быть готовы к этому. Смотрите onLoaderFinished для более подробного обсуждения методов обратного вызова.
Обратите внимание, что метод initLoader () вернет созданный объект Loader, но нам не нужно хранить ссылку на загрузчик. LoaderManager автоматически управляет жизненным циклом Loader. LoaderManager запускает и останавливает загрузку, когда это необходимо, и поддерживает состояние загрузчика и связанного с ним содержимого и данных. Как это показывает, мы редко имеем дело с загрузчиком напрямую (хотя для примера использования методов загрузчика для тонкой настройки поведения загрузчика см.LoaderThrottleПример), наиболее распространенная ситуация заключается в том, что вы используете обратные вызовы LoaderManager.LoaderCallbacks для вмешательства в процесс загрузки загрузчика при возникновении определенного события. Для получения дополнительной информации по этой теме см. Использование обратных вызовов LoaderManager.
Restarting a Loader
Как показано выше, при использовании initLoader (), если указанный идентификатор уже существует, он будет повторно использовать существующий Loader. Если нет, то создается новый Loader. Иногда вы можете отказаться от старых данных, а затем снова загрузить новые.
Чтобы отказаться от старых данных, вы можете использовать reStartLoader (). НапримерSearchView.OnQueryTextListener
Класс реализации перезапускает Loader при изменении пользовательского запроса. Чтобы использовать пересмотренный фильтр поиска для нового запроса, необходимо перезапустить Loader.
Using the LoaderManger Callbacks
LoaderManager.LoaderCallback — это интерфейс обратного вызова для взаимодействия клиента с LoaderManager.
Ожидается, что загрузчики, особенно CursorLoader, сохранят свои данные после их остановки. Это позволяет приложению сохранять свои данные во время выполнения метода onStop () или onStart () действия или фрагмента. Таким образом, когда пользователь возвращается в приложение, ему не нужно ждать перезагрузки данных. Вы можете использовать метод обратного вызова LoaderManager.LoaderCallback, чтобы узнать, когда генерируется новый Loader, а затем сообщить приложению, когда пора прекратить использование данных Loader.
LoaderManager.LoaderCallback включает следующие методы обратного вызова:
1. onCreateLoader () — генерирует новый загрузчик, соответствующий идентификатору, и возвращает загрузчик
2. onLoadFinished () — вызывается, когда ранее сгенерированный Loader завершил загрузку своих данных
3. onLoaderReset () — вызывается при сбросе ранее сгенерированного загрузчика. После сброса загрузчик его данные становятся недействительными.
Эти методы будут подробно описаны ниже
Когда вы пытаетесь получить доступ к Loader (например, через initLoader ()), он проверит, существует ли Loader, соответствующий указанному идентификатору. Если он не существует, он вызовет метод onCreateLoader LoaderManager.LoaderCallback, где вы можете создать новый Loader. Например, CursorLoader — это класс, предоставляемый системой, которая реализует Loader. Конечно, вы также можете реализовать свой собственный класс загрузчика.
Например, в методе обратного вызова onCreateLoader вы создаете CursorLoader, а для создания Loader вам необходимо вызвать его метод построения. Для метода построения требуются следующие параметры. Эти серии параметров используются для запроса ContentProvider:
1.uri — URI найденного контента
2.projection — возвращает список столбцов. Если передать значение null, будут возвращены все столбцы, но это неэффективно.
3.selection — Фильтр возвращенной строки, соответствующий формату предложения SQL WHERE (но не включая само поле WHERE), при передаче значения null будут возвращены все строки (все записи), соответствующие uri.
4. selectionArgs — может включать подстановочные знаки в выборе параметров? , Эти подстановочные знаки будут заменены значением из параметра selectionArgs. Они будут отображаться в списке по порядку и будут упакованы в строки.
5. sortOrder — Как отсортировать строки возвращаемых результатов, в соответствии с оператором SQL ORDER BY (но не включая само ключевое слово ORDER BY), при передаче значения null будет использоваться метод сортировки по умолчанию, который может быть не в порядке.
Этот метод вызывается, когда ранее сгенерированный Loader завершил загрузку. Вызов этого метода должен предшествовать освобождению данных, заполняющих загрузчик. На данный момент вам необходимо удалить все использование старых данных (потому что данные будут выпущены немедленно). Но вы не должны выполнять свои собственные операции по выпуску этих данных, поскольку Loader владеет этими данными, а Loader должен обращать внимание на эти данные и управлять ими.
Как только Загрузчик узнает, что приложение больше не будет его использовать, Загрузчик выпустит данные. Например, если данные поступают из курсора CursorLoader, вам не следует вызывать собственный метод close (). Если курсор находится в CursorAdapter, следует использовать метод swapCursor (), чтобы старый курсор не закрывался. Например:
Этот метод вызывается, когда ранее сгенерированный загрузчик сбрасывается, а затем данные становятся недействительными. Этот обратный вызов сообщает вам, что данные должны быть освобождены, поэтому вы можете удалить ссылку на них.
Следующий класс реализации вызывает метод swapCursor (), и переданный параметр имеет значение null:
Example
Пример, показанный ниже, является полной реализацией фрагмента, который использует Loader для отображения данных LIstVIiew.Данные отображения этого просмотра списка получены от поставщика контента запроса контакта. Используйте CursorLoader для управления и запроса провайдера.
Для приложения, которое обращается к контактам пользователя, как в примере, показанном ниже, файл манифеста должен включать разрешение READ_CONATACTS.
More Examples
В ApiDemos есть несколько различных примеров, которые объясняют, как использовать загрузчики:
1. LoaderCursor — полная версия фрагмента, показанного выше
2.LoaderThrottle — An example of how to use throttling to reduce the number of queries a content provider does when its data changes
Для получения дополнительной информации о загрузке и установке примеров SDK см.Getting the Samples
Источник