OnLoadFinished() вызывается дважды

Я пытаюсь выяснить, не делаю ли я что-то не так с загрузчиками. Я использую библиотеку поддержки, и у меня есть фрагмент, который в onCreate() вызывает initLoader(), устанавливая себя как LoaderCallbacks, однако при вращении он дважды получает результат в onLoadFinished(), один раз в результате вызова init (и у него уже есть данные), и один раз в результате того, что FragmentActivity перебирает все загрузчики в onStart() и доставляет результат, поскольку у него уже есть данные.

Если я вызываю init только один раз (при первом запуске фрагмента), он не устанавливает себя в качестве обратного вызова для загрузчика, поэтому он вообще не получает вызов onLoadFinished. Кажется, что onLoadFinished следует вызывать только один раз, поскольку в onLoadFinished() могут выполняться некоторые дорогостоящие действия (например, адаптеры списка очистки и т. д.), поэтому я просто пытаюсь выяснить, является ли это ошибкой или я просто вызов init в неподходящее время или что-то еще.

У кого-нибудь есть понимание этого вопроса?


person Matt Kranzler    schedule 06.02.2013    source источник
comment
Я не уверен, почему это происходит, но вызов getLoaderManager().initLoader(0, null, this); в onResume() кажется решением для многих людей (включая меня). См. stackoverflow.com/a/14524031/1617737 .   -  person ban-geoengineering    schedule 26.01.2016
comment
Это лучший ответ, который я нашел по этому поводу: stackoverflow.com/a/17324776/2578070   -  person James Wiley    schedule 08.03.2016


Ответы (5)


У меня была аналогичная проблема, и причина заключалась в том, что в моем коде были initLoader и restartLoader. В зависимости от действий пользователя мой запрос мог измениться, поэтому мне нужно было перезапустить загрузчик.

Решение состояло в том, чтобы использовать только restartLoader, даже в методе обратного вызова onResume заменить initLoader на restartLoader.

person Mussa    schedule 28.05.2015

Это довольно старый вопрос, но для будущих читателей у меня есть альтернативное решение. По сути, в итоге я перезапустил загрузчик, если он существовал.

public void onActivityCreated(Bundle savedInstanceState) {
...
       if(getLoaderManager().getLoader(Constants.LOADER_ID) == null) {
            getLoaderManager().initLoader(Constants.LOADER_ID, null, this);
        } else {
            getLoaderManager().restartLoader(Constants.LOADER_ID, null, this);
        }

...
}

Это решило мою проблему с тем, что при повороте экрана загрузчик запускался дважды. Также обратите внимание, что это необходимо только для меня на Android ‹ 6, который я тестировал. В Android 6 такой проблемы нет.

person Qben    schedule 29.11.2015
comment
Это решение может работать, но имеет ту же проблему, что и Алекс Локвуд, упомянутый ранее. - person Carlos Hernández Gil; 12.09.2016

Я испытываю ту же проблему сам, без хорошего решения. Это похоже на ошибку в среде Android, вот аналогичная ветка, в которой предлагается решение поместить initLoader() в onResume() - я пробовал, и это работает, onLoadFinished() вызывается только один раз: Android: LoaderCallbacks.OnLoadFinished вызывается дважды

person Gordon Freeman    schedule 14.02.2013

См. мой пост в Android: LoaderCallbacks.OnLoadFinished вызывается дважды

У меня была аналогичная проблема при перезапуске фрагментов в ViewPager. Мое решение состоит в том, чтобы удалить загрузчик, как только я закончу с ним (в конце onLoadFinished), позвонив

getLoaderManager().destroyLoader(LOADER_ID);

Надеюсь, поможет!

person Matt    schedule 04.03.2014
comment
Это очень плохое решение... уничтожение Loader также уничтожит все связанные с ним данные. Одним из основных преимуществ Loaders является то, что данные сохраняются при изменении конфигурации (например, при изменении ориентации и т. д.)... уничтожение этих данных означает, что вам нужно будет повторно запрашивать данные каждый раз, когда происходит изменение конфигурации. - person Alex Lockwood; 19.12.2014

Это похоже на неправильную реализацию/ошибку загрузчика фреймворка. 1. посмотрите, что я получил из сообщений Log.v(LOG_TAG, ...) от каждого важного метода/обратного вызова после поворота экрана:

...: .initLoader() 100
...: onStartLoading()
...: onLoadFinished()
...: updateUi(); articles size=10
...: loadInBackground()
...: getInputStream() - HttpRequest
...: onLoadFinished()
...: updateUi(); articles size=10

2. Как видите, все после 'updateUi()' здесь не нужно.

person Andrij    schedule 10.05.2020