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 там.

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

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

Другие вопросы по тегам