Использование Loader с фрагментом /Activity с виджетами UI, запускающими обновления содержимого загрузчиков
Я использую некоторое время API-интерфейсы Loaders. Я нашел отличное решение и самый элегантный дизайн для решения общей проблемы большинства приложений: отображение "обработанного" динамического контента с минимальным вмешательством в Fragment
/Activity
- ответственность за загрузку данных и всей логики, лежащей в основе, заключена в загрузчике...
проблема начинается, когда пользовательский интерфейс, инициализированный данными, возвращаемыми загрузчиком, вызывает изменение в тех же данных, которые он инициализировал.
чтобы было понятнее, скажем, что наша основная активность или фрагмент отображают бесконечный список сообщений (например, приложение Facebook или Google+). Давайте предположим, что это приложение использует какой-то AsyncTaskLoader
или CusorLoader
:
ListView
отображение списка сообщений будет инициализировано данными загрузчиков в нужное время Activity
жизненный цикл.
Теперь давайте скажем, что тем временем GCM получил толчок и вызвал обновление источника данных. все же все хорошо: загрузчик обновит активность с изменением данных.
На следующем сканировании все становится беспорядочно:
1) пользователь нажал на кнопку "Мне нравится" одного из постов
2) фоновая задача / служба запускает сетевую операцию для обновления статуса записи на сервере
3) Пользовательский интерфейс должен немедленно измениться (набор данных уведомления адаптера изменился), не дожидаясь ответа по сети, потому что пользователь должен знать, что что-то происходит (может быть также не полноэкранный индикатор выполнения, блокирующий)
4) сетевой запрос завершен (не обязательно успешен)
в следующем сканировании все очень быстро выходит из-под контроля во всех аспектах:
Те же виджеты, которые предполагается обновлять исключительно под ответственность загрузчиков, вынуждены обновляться локально, чтобы отразить временное состояние, которое не обязательно будет "конечным" состоянием источника данных (например, если сетевой ответ будет неудачным для всех типов). причин..)
Теперь предположим, что сетевая операция еще не завершена и все еще находится в полете, и по другой причине (GCM Push / другая фоновая операция, которая находилась в середине выполнения) загрузчик перезагружается и уведомляет активность о появлении новых данных. сейчас это уже очень неудобная ситуация: появились новые данные, но пользовательский интерфейс все еще находится в режиме, который я описал ранее. Я обнаружил, что реализую логику, которая разрешает такие конфликты, и решает, должен ли пользовательский интерфейс реагировать на источник данных загрузчика или нет.
Теперь умножьте эту проблему на количество действий, которые вы можете выполнить над сообщениями, и количество сообщений.
Исходя из этого, я пришел к выводу, что Loader является очень проблемным решением, когда источник данных может сильно отличаться от операций "записи", запускаемых из того же пользовательского интерфейса, инициализированного этим источником данных.
но, с другой стороны, у меня нет никакого другого решения для элегантного дизайна проблемы, которую я описал, хотя это очень распространенная ситуация.
Мой вопрос в основном таков:
Есть ли какие-либо рекомендации по использованию загрузчиков в таких сценариях, как я описал?
Есть ли лучшее решение / API-компоненты или дизайн, о котором я не думаю, что он отвечает таким требованиям?
заранее спасибо,
1 ответ
Дело не в том, что Loader является очень проблемным решением. Скорее, вызовы веб-службы и push-уведомления являются асинхронными, и проблема интеграции полученных в результате данных результатов в существующий набор данных (и управления ими в рамках Activity
/ Fragment
жизненный цикл) - это сложная ситуация, которую структура пытается максимально упростить и обобщить. Эти обобщения являются LoaderManager
, ContentProvider
а также SyncAdapter
классы и связанные с ними методы.
Не видя ни одного из ваших существующих кодов и не предлагая каких-либо других расширенных решений, вот самое простое, что я могу убедить вас попробовать (если вы еще не пробовали): всякий раз, когда завершается вызов веб-службы или получено уведомление, позвоните либо
Loader.reset();
или же
LoaderManager.restartLoader();
и убедитесь, что вы очистите свой Adapter
как
@Override
public void onLoaderReset(Loader<Cursor> loader) {
// clear your adapters here
listview.setAdapter(null);
viewpager.setAdapter(null);
}
Это загружает недавно добавленные данные в представление. Программист несет ответственность за обновление набора данных после завершения асинхронной задачи.