Что на самом деле делает AsyncTaskLoader.deliverResult()?
Я пытаюсь понять некоторые тонкости AsyncTaskLoaders. Для других это может быть очевидно, но я не могу найти однозначного примера или определения, которое демонстрирует и объясняет, что происходит, когда вы переопределяете deliverResult()
метод. Что на самом деле доставляется? Как это взаимодействует с вызывающим объектом? Я вижу использование super.deliverResult
, который передает приватный объект из класса. Итак, автоматически ли загрузчик знает, что связать с "доставленным результатом". Я полностью сбит с толку.
4 ответа
Кажется, я немного опоздал на вечеринку, но все равно...
Одно из главных преимуществ этого промежуточного шага между фоновой загрузкой и обратным вызовом потока пользовательского интерфейса onLoadFinished()
быть вызванным
loadInBackground()
deliverResult()
а также- обратный звонок
onLoadFinished()
является то, что это дает нам возможность сократить весь процесс загрузки изнутри AsyncTaskLoader
учебный класс. И это может быть полезно для кэширования результата загрузки в AsyncTaskLoader и предотвращения фоновой загрузки, если есть кэшированные данные.
И зачем нам это делать? Разве весь смысл загрузчиков не в том, что они имеют дело с этими страшными проблемами жизненного цикла активности (например, вращение устройства), поддерживают состояние (например, кэширование данных) и имеют средства для обновления при изменении базовых данных (CursorLoader)?
Ну да, но это еще не все.
Рассмотрим этот вариант использования:
У вас есть запущенное приложение (приложение с AsynTaskLoader), и оно уже загрузило данные в ваш пользовательский интерфейс. Затем вы переключаетесь на свое приложение Twitter, чтобы проверить некоторые новости и вернуться к своему приложению. Без кеширования, вернувшись в ваше приложение, загрузчик выполнит его перезагрузку. Это поведение отличается от того, которое происходит после изменения конфигурации, например, при повороте устройства, и в этом случае перезагрузка не происходит.
Итак, как бы мы тогда запретили загрузчику повторно извлекать данные в случае, если мы просто отправляем наше приложение в фоновый режим, а затем снова возвращаемся к нему?
Решение
- Создайте переменную члена кеша в вашем
AsyncTaskLoader
реализация. - Override
deliverResult()
так что сначала вы сохраняете полученные данные в своем кэше, прежде чем вызывать реализацию суперкласса deliveryResult(). - В
onStartLoading()
проверьте, есть ли кэшированные данные, и если так, пусть ваш AsyncTaskLoader просто доставит это. В противном случае начните загрузку.
Вот ссылка на пример приложения, которое реализует это поведение. Это всего лишь "игрушечное приложение" и, как таковая, часть текущей версии базового курса Udacity "Разработка приложений для Android". А вот ссылка на соответствующее видео в этом курсе, посвященное этой проблеме. (Курс бесплатный, но вам все равно придется зарегистрироваться с Udacity).
Вкратце, это приложение демонстрирует пользовательский интерфейс, в котором пользователь может ввести поисковый запрос для поиска репозиториев GitHub (через GitHub API), показывая результирующий поисковый URL в TextView, а также необработанный JSON, извлеченный из GitHub в другом TextView.,
Все действие происходит просто MainActivity.java
и соответствующая часть здесь находится в пределах AsyncTaskLoader
это реализовано как анонимный внутренний класс:
Для шага 1 просто введите переменную-член в свой
AsyncTaskLoader
реализация, которая предназначена для использования в качестве кеша данных./* This String will contain the raw JSON from the results of our Github search */ String mGithubJson;
Для шага 2 переопределить
deliverResult()
как кешировать результат загрузки.
когдаloadInBackground()
закончил, передает свое возвращаемое значениеdeliverResult()
, В любом случае, это так, но теперь, когда мы переопределили метод deliveryResult (), мы можем сразу же перейти и сохранить полученные данные в переменную-член кэша, которую мы создали с таким хорошим предвидением. И, наконец, мы подключаемся к реализации суперкласса deliveryResult () сsuper.deliverResult()
который передаст результат методу обратного вызоваonLoadFinished()
работает в потоке пользовательского интерфейса.@Override public void deliverResult(String githubJson) { mGithubJson = githubJson; super.deliverResult(githubJson); }
Для шага 3, проверьте в
onStartLoading()
есть ли у нас кешированные данные.
Если у нас нет кэшированных данных (пока), просто начните загрузку с вызоваforceLoad()
, Но если у нас есть кэшированные данные, просто позвонитеdeliverResult(yourCachedDataGoesHere)
и передать кэшированные данные в качестве аргумента.if (mGithubJson != null) { deliverResult(mGithubJson); } else { forceLoad(); }
Итак, если вы теперь переключаетесь между вашим приложением и некоторыми другими приложениями, вы заметите, что перезагрузка не происходит, поскольку загрузчик просто использует ваши кэшированные данные.
Предположим, что когда данные загружаются в фоновом режиме, в это время пользователь нажимает кнопку HOME и создает приложение, когда пользователь возвращается в приложение, загрузка завершена. Итак, у нас уже есть данные, то AsyncTaskLoader
позвоню deliverResult()
метод, доставить данные в onLoadFinished()
метод для отображения.
Когда пользователь возвращается в приложение, onStartLoading()
вызывается раньше loadInBackground()
, В этом методе мы можем проверить, являются ли наши данные пустыми или нет, если не пустыми, мы вызываем deliverResult()
и отправить результат onLoaderFinished()
, так что это может помешать перезагрузить данные.
Когда мы нажимаем HOME, существует приложение, а затем возвращаемся, оно не будет создавать новый загрузчик, вместо этого старый загрузчик будет пытаться загрузить данные.
Единственный ответ, который я могу найти, который имеет какой-либо смысл, основан на описании этой ссылки.
"Зарегистрированный слушатель получает результаты Loader, когда завершает загрузку. Для каждого из LoadersManager регистрирует OnLoadCompleteListener, который перенаправляет доставленные результаты Loader клиенту с вызовом onLoadFinished(Loader loader, D result). Loaders должен доставить результаты этим зарегистрированным слушателям с помощью вызова Loader#deliveryResult(D result)."
Похоже, что deliveryResult используется, когда у вас есть слушатели AsyncTask и вы хотите отправить результаты обратно им. Я бы сказал, что это необычно. Документация Android еще менее наглядна:
"Посылает результат загрузки зарегистрированному слушателю. Должен вызываться только подклассами. Должен вызываться из основного потока процесса.
параметры
данные: результат загрузки "
DeliveryResult работает после завершения doInbackground. Он отправляет результат D (возвращаемый doInBackground) вызывающему потоку. Возможно, вы захотите переопределить его для очистки данных, но вместо этого вы можете выполнить очистку в doInBackground, не переопределяя deliveryResult.