LoaderCallbacks.onLoadFinished не вызывается, если изменение ориентации происходит во время запуска AsyncTaskLoader
Использование android-support-v4.jar и FragmentActivity (без фрагментов в этой точке)
У меня есть AsyncTaskLoader, который я начинаю загружать, а затем меняю ориентацию, пока фоновый поток все еще работает. В моих журналах я вижу ответы, которые поступают к фоновым запросам. Ответы завершены, и я ожидаю, что onLoadFinished() будет вызван, но это никогда не будет.
Как средство устранения неполадок, в манифесте, если я устанавливаю андроид: configChanges = "ориентация" onLoadFinished() вызывается как ожидалось.
Моя активность реализует обратные вызовы загрузчика. В источнике для LoaderManager.initLoader() я вижу, что если загрузчик уже существует, новый обратный вызов устанавливается на внутренний класс объекта LoaderInfo, но я не вижу, где снова вызывается Loader.registerListener(). registerListener, похоже, вызывается только при вызове LoaderManagerImpl.createAndInstallLoader().
Я подозреваю, что, поскольку действие уничтожается и воссоздается при изменении ориентации, и поскольку оно является слушателем для обратных вызовов, новая активность не регистрируется для уведомления.
Может ли кто-нибудь подтвердить мое понимание и какое решение так вызывается onLoadFinished после изменения ориентации?
Ответы
Ответ 1
Николай определил проблему - Спасибо.
Я вызывал initLoader fron onResume(). В документации на Android указано:
"Обычно вы инициализируете загрузчик в рамках действия onCreate() метод или внутри метода фрагмента onActivityCreated().
Прочитайте "типично" как немного более решительно, чем когда-либо, когда дело касается жизненного цикла изменения конфигурации.
Я перевел мой вызов initLoader на onCreate(), и это решило мою проблему.
Я думаю, причина в том, что в FragmentActivity.onCreate() коллекция LoaderManager вытащили из LastNonConfigurationInstance и в FragmentActivity.onStart() появилась некоторая работа по запуску в отношении Loaders и LoaderManagers. Вещи уже находятся в процессе к тому времени, когда вызывается вызовResume(). Когда загрузчик требуется создать экземпляр в первый раз, вызов initLoader извне onCreate() все еще работает.
Ответ 2
На самом деле это не вызов initLoader()
в onCreate()
, который его исправляет. Это вызов getLoaderManager()
. Итак, что происходит, когда происходит перезапуск активности, он уже знает о загрузчиках. Он пытается перезапустить их, когда ваша активность попадает на onStart()
, но затем он обращается к этому коду в FragmentHostCallback.doLoaderStart()
*:
void doLoaderStart() {
if (mLoadersStarted) {
return;
}
mLoadersStarted = true;
if (mLoaderManager != null) {
mLoaderManager.doStart();
} else if (!mCheckedForLoaderManager) {
mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
// WTF: Why aren't we calling doStart() here?!
}
mCheckedForLoaderManager = true;
}
Так как getLoaderManager() еще не был вызван, mLoaderManager
имеет значение null. Поэтому он пропускает первое условие и вызов mLoaderManager.doStart()
.
Вы можете проверить это, просто поместив вызов getLoaderManager()
в onCreate()
. Вам не нужно вызывать загрузчики init/restart.
Это действительно кажется ошибкой для меня.
* Это путь кода, даже если вы не используете фрагменты, поэтому не путайте это.