LoaderCallbacks.onLoadFinished не вызывается, если изменение ориентации происходит во время выполнения AsyncTaskLoader
Использование android-support-v4.jar и FragmentActivity (на данный момент нет фрагментов)
У меня есть AsyncTaskLoader, который я начинаю загружать, а затем меняю ориентацию, пока фоновый поток еще работает. В моих журналах я вижу ответы, поступающие на фоновые запросы. Ответы завершены, и я ожидаю, что onLoadFinished() будет вызван, но это не так.
В качестве средства устранения неполадок, в манифесте, если я установил android:configChanges="direction" onLoadFinished() вызывается, как и ожидалось.
Моя активность реализует обратные вызовы загрузчика. В исходном коде LoaderManager.initLoader() я вижу, что если загрузчик уже существует, то для нового обратного вызова устанавливается класс внутреннего объекта LoaderInfo, но я не вижу, где Loader.registerListener() вызывается снова. registerListener, кажется, вызывается только при вызове LoaderManagerImpl.createAndInstallLoader().
Я подозреваю, что поскольку активность изменяется и воссоздается при изменении ориентации и поскольку она является прослушивателем обратных вызовов, новая активность не регистрируется для уведомления.
Кто-нибудь может подтвердить мое понимание и что такое решение, чтобы onLoadFinished вызывалось после смены ориентации?
2 ответа
Николай определил проблему - Спасибо.
Я звонил initLoader из onResume(). Документация Android гласит:
"Обычно вы инициализируете Loader в методе действия onCreate() или в методе фрагмента onActivityCreated()".
Прочитайте "как правило" как немного более решительное, чем я, когда речь шла о жизненном цикле изменения конфигурации.
Я переместил мой вызов initLoader в onCreate(), и это решило мою проблему.
Я думаю, что причина в том, что в FragmentActivity.onCreate() коллекция LoaderManagers извлекается из LastNonConfigurationInstance, а в FragmentActivity.onStart() есть некоторая начальная работа, связанная с Loaders и LoaderManager. К моменту вызова onResume () все уже выполняется. Когда загрузчик должен быть создан в первый раз, вызов initLoader извне onCreate() все еще работает.
Это на самом деле не призыв к 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
нулевой. Поэтому он пропускает первое условие и вызов mLoaderManager.doStart()
,
Вы можете проверить это, просто позвонив getLoaderManager()
в onCreate()
, Вам не нужно вызывать загрузчики init / restart там.
Это действительно кажется мне ошибкой.
* Это путь к коду, даже если вы не используете фрагменты, так что не смущайтесь.