loaders (and why we should use them)
DESCRIPTION
In this presentation I'm talking about powerful tool for asynchronous loading which is provided by Android framework - loaders. Why guys from Android team added this tool and how we can customise it? We'll try to find answers for these questions.TRANSCRIPT
почему с ними стоит дружить?
Loaders
Проблемахотим плавный графический интерфейс без
тормозов
Решениевыносим все время-затратные процессы в
фон
Простейший случай
Инструменты для решениявстроенные в Java классы для роботы с
многопоточностью (Thread, Runnable, etc)
Недостатки● никаких “удобств” для организации
межпроцессного взаимодействия ○ много кода - легко запутаться и допустить ошибку
● не адаптированны для Android’а○ проблемы с производительностью (если не
использовать пул потоков)○ ничего не знают про жизненный цикл
компонентов
Частное решение - AsyncTask● Значительно упрощает межпроцессное
взаимодействие● Использует пул (производительность++)
Активности не вечныочень не вечны...
Проблемафоновые процессы должны “переживать” пересоздание активности и доставлять
результат в новую активность
Решениеиспользовать компоненты отвязанные от
контекста активности
Инструменты для решения● сервис (Robospice)● RxJava + фрагменты● лоадеры● веселые комбинации из предыдущих трех
Справедливости ради, нужно отметить, что асинктаски все еще пользуются популярностью
Обычно, случается совсем не сразу после сокрытия активности + сетевые запросы не настолько длинные
Сервисы+маловероятно, что система убъет приложение+много хорошо развитых библиотек-трудности взаимодействия с сервисом-библиотеки Гуглом не поддерживаются, судьба их туманна
RxJava+ бОльшая ориентированность на событийную модель-+другая парадигма программирования-без Retrolambda очень много шаблонного кода
Кто такой этот ваш лоадер?Это кто-то умеющий:● загрузить данные● хранить их в себе● отслеживать изменения в данных и доставлять
новые данные● реагировать на события жизненного цикла
Состояния Loader’а● started - лоадер загружает/хранит данные и следит
за обновлениями● stopped - лоадер следит за обновлениями, но не
сообщает о них● reset - лоадер не содержит в себе данных и не
следит за изменениями
LoaderManager● привязывается к активности/фрагменту и
переживает configuration change
● хранит ссылки на лоадеры
● обеспечивает жизненный цикл лоадеров
Методы LoaderManager‘а○ initLoader() - создает и запускает лоадер. Если
лоадер содержит данные - возвращает их немедленно
○ restartLoader() - создает или пересоздает лоадер,
при этом данные загружаются заново
○ destroyLoader() - уничтожает лоадер
LoaderCallbacksТочка коммуникации View и LoaderManager
public class SampleActivity extends Activity implements LoaderManager.LoaderCallbacks<D> {
public Loader<D> onCreateLoader(int id, Bundle args) { // фабричный метод для лоадера }
public void onLoadFinished(Loader<D> loader, D data) { // обработка результатов }
public void onLoaderReset(Loader<D> loader) { // освобождение ресурсов }}
До API level 11 у активности были такие методы:
● public void startManagingCursor(Cursor)
● public void stopManagingCursor(Cursor)
● public Cursor managedQuery(Uri, String, String, String, String)
Почему все началось с курсоров?они и до сих пор есть, но deprecated
Но что-то было не так...+активность сама обслуживает курсор-курсор пересоздавался при пересоздании активности-все в UI потоке
getLoaderManager().initLoader(LOADER_ID, null, new LoaderManager.LoaderCallbacks<Cursor>() { @Override public Loader<Cursor> onCreateLoader(int i, Bundle bundle) { return new CursorLoader(getActivity(), "content://com.foo.bar/dog", null, null, null, null); } @Override public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) { if (cursor != null && cursor.moveToFirst()) someView.setText(cursor.getString(0)); } @Override public void onLoaderReset(Loader<Cursor> cursorLoader) { // если бы тут был курсор адаптер, мы бы свапнули курсор }});
CursorLoader все порешал
Реализация собственного Loader’а● рекомендуется использовать AsyncTaskLoader
● нужно будет переопределить○ loadInBackground()
○ onStartLoading()
○ onStopLoading()
○ onReset()
○ onCanceled()
○ deliverResult(D results)
● loadInBackground()
○ Фоновая операция. Именно в ней данные загружаются.
● onStartLoading()
○ проверить нет ли у нас загруженных данных и если есть,
то вернуть их немедленно
○ если данных нет, то форсировать их загрузку
○ запустить механизм, который будет отслеживать
изменения в данных
● onStopLoading()
○ перестать уведомлять о новых данных, но быть готовым к
старту
● onReset()
○ остановить загрузку
○ прекратить отслеживать изменения данных
● onCanceled()
○ попытаться остановить текущую загрузку
○ почистить загруженные данные
● deliverResult(D results)
○ если лоадер в reset состоянии - освободить ресурсы
○ иначе доставить новые данные и освободить ресурсы
устаревших данных
Сейчас я полезу в идею, показать вам немного кода для кастомного лоадера.
Наверняка что-то повлится, так что заранее прошу прощения за косячки ;)
Loader’ы+безболезненно переживают пересоздание+хорошо документированны+”официальный” инструмент-приложение могут убить-жизненный цикл не самый простой
Мораль● не стоит пренебрегать лоадерами
● для простого сетевого взаимодействия лоадеры
вполне могут подойти
● можно использовать лоадеры как фасад к
другому инструменту асинхронной загрузки
● Серия статей про Loaders (by Alex Lockwood)● Android networking without pain (презентация)● Modern techniques for implementing REST clients
on Android 4.0 and below● CWAC-LoaderEx and Failed Abstractions● Android tutorial to learn through small projects
(оно на китайском)● Пример на GitHub
Интересности найденные в процессе подготовки презенташки
это все ссылочки - можно кликать
Спасибо за внимание!
Мои контакты:Миша Пустовит
Stanfyhttps://google.com/+ПустовитМихаил