Собственный LoaderManager и загрузчик остаются сломанными?

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

Первоначально я начал тестировать это поведение, потому что заметил следующую ошибку в библиотеке поддержки LoaderManager и хотел проверить, работает ли она лучше с собственными API: Загрузчик не может сохранить себя во время определенного изменения конфигурации

Я написал простую тестовую активность, чтобы отобразить проблему:

public class MainActivity extends Activity implements LoaderManager.LoaderCallbacks<String>, View.OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Button button = new Button(this);
        button.setText("Click Me");
        button.setOnClickListener(this);

        setContentView(button);
    }

    @Override
    protected void onResume() {
        super.onResume();
        getLoaderManager().initLoader(1, null, this);
    }

    @Override
    public Loader<String> onCreateLoader(int id, Bundle args) {
        return new StringLoader(this);
    }

    @Override
    public void onLoadFinished(Loader<String> loader, String data) {
        Log.d("LoaderTest", "Loader Finished "+loader.toString());
    }

    @Override
    public void onLoaderReset(Loader<String> loader) {
        Log.d("LoaderTest", "Loader Reset "+loader.toString());
    }

    @Override
    public void onClick(View v) {
        startActivity(new Intent(this, SecondActivity.class));
    }

    private static class StringLoader extends Loader<String> {

        public StringLoader(Context context) {
            super(context);
        }

        @Override
        protected void onStartLoading() {
            deliverResult("Hi Mom!");
        }
    }
}

SecondActivity в этом примере просто фиктивный и может быть чем угодно. Первоначально он был добавлен для проверки случая Launch -> Rotate -> Return, описанного в связанной проблеме SO (которая до сих пор не работает в библиотеке поддержки).

Запустив это приложение с компонентами android.support.v4.FragmentActivity и Loader из android.support.v4, поведение работает, как и ожидалось (за исключением ошибки, описанной в ссылке выше). Устройство можно вращать несколько раз, и при каждом вращении:

  • Тот же экземпляр LoaderManager возвращается из getLoaderManager()
  • Тот же экземпляр Loader передается в onLoadFinished()
  • onLoadFinished() вызывается сразу после каждого вызова initLoader()

Теперь используйте приведенный выше пример со всеми «родными» компонентами для Activity, LoaderManager, AsyncTaskLoader и т. д., и поведение резко изменится. Снова поверните устройство несколько раз и:

  • Теперь onLoadFinished() будет называться только каждая вторая ротация.
  • Когда вызывается onLoadFinished(), переданный экземпляр Loader всегда является новым.
  • LoaderManager также является другим экземпляром в это время.
  • При четных поворотах экземпляр LoaderManager не меняется и возвращает тот же Loader из initLoader(); однако onLoadFinished() никогда не срабатывает, потому что LoaderManager утверждает, что не был запущен (т. е. его внутреннее mStarted ложно)

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

Может ли кто-нибудь проверить это поведение или показать, что я делаю неправильно?


person devunwired    schedule 17.12.2013    source источник
comment
Почему вы отказываетесь от поддерживаемых версий? Они всегда будут более согласованными версиями для всех версий платформ, и я уверен, что у большинства приложений будет причина использовать что-то из них (будь то ViewPager или что-то еще).   -  person ianhanniballake    schedule 17.12.2013
comment
Если вас беспокоит только ViewPager, существует версия библиотеки поддержки v13, которая не включает большую часть всех других API. Немного недальновидно думать, что в какой-то момент в будущем мы захотим перестать включать обратно перенесенный код в APK, как только минимальная версия будет поддерживать это решение. Если, конечно, там нативная реализация не сломана :)   -  person devunwired    schedule 17.12.2013
comment
Я использую ViewPager только в качестве примера. Вложенные фрагменты, PrintHelper, getExternalCacheDirs, ActionBarDrawerToggle/NavigationDrawer, вся структура mediarouter и другие — все это причины, по которым вы должны продолжать использовать библиотеку поддержки, а с ProGuard влияние APK гораздо меньше беспокоит. Также обратите внимание, что версия библиотеки поддержки v13 включает в себя всю библиотеку поддержки v4, поэтому вы ничего там не сохраняете.   -  person ianhanniballake    schedule 17.12.2013
comment
Будет ли такое же поведение, если вы переместите initLoader() из onResume() в onCreate()?   -  person Alex Lockwood    schedule 18.12.2013
comment
Кроме того, вы пытались установить LoaderManager.enableDebugLogging(true)? Никогда не знаешь... может поможет.   -  person Alex Lockwood    schedule 18.12.2013
comment
На каком уровне API вы обнаружили неисправное поведение?   -  person louielouie    schedule 18.12.2013
comment
@AlexLockwood, вы можете попробовать пример для себя (я надеялся, что люди это сделают), поведение, похоже, не меняется независимо от того, где инициализируется загрузчик.   -  person devunwired    schedule 18.12.2013
comment
@louielouie До сих пор это согласовывалось со всем, от ICS до KitKat.   -  person devunwired    schedule 18.12.2013