Подтвердить что ты не робот

LoaderCallbacks.onLoadFinished не вызывается, если изменение ориентации происходит во время запуска AsyncTaskLoader

Использование android-support-v4.jar и FragmentActivity (без фрагментов в этой точке)

У меня есть AsyncTaskLoader, который я начинаю загружать, а затем меняю ориентацию, пока фоновый поток все еще работает. В моих журналах я вижу ответы, которые поступают к фоновым запросам. Ответы завершены, и я ожидаю, что onLoadFinished() будет вызван, но это никогда не будет.

Как средство устранения неполадок, в манифесте, если я устанавливаю андроид: configChanges = "ориентация" onLoadFinished() вызывается как ожидалось.

Моя активность реализует обратные вызовы загрузчика. В источнике для LoaderManager.initLoader() я вижу, что если загрузчик уже существует, новый обратный вызов устанавливается на внутренний класс объекта LoaderInfo, но я не вижу, где снова вызывается Loader.registerListener(). registerListener, похоже, вызывается только при вызове LoaderManagerImpl.createAndInstallLoader().

Я подозреваю, что, поскольку действие уничтожается и воссоздается при изменении ориентации, и поскольку оно является слушателем для обратных вызовов, новая активность не регистрируется для уведомления.

Может ли кто-нибудь подтвердить мое понимание и какое решение так вызывается onLoadFinished после изменения ориентации?

4b9b3361

Ответ 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.

Это действительно кажется ошибкой для меня.

* Это путь кода, даже если вы не используете фрагменты, поэтому не путайте это.