Восстановление докладчиков для фрагментов ViewPager (MVP)

Я пытаюсь реорганизовать существующее приложение для использования архитектуры MVP. Одно из мероприятий имеет ViewPager с тремя фрагментами. Каждый фрагмент связан с докладчиком. Чтобы быть точным - каждый докладчик, когда он создан, получает View работать с, то есть Fragment, Пока я создаю этих докладчиков внутри ViewPagerАдаптер - конкретно в getItem(int position) метод.

Fragment fragment = FirstFragment.newInstance();
FirstPresenter presenter = new FirstPresenter(repo, (FirstContract.View) fragment, projectId, userId);

Проблема, с которой я сталкиваюсь, заключается в том, что если процесс завершается, а затем перезапускается, ViewPager имеет свой жизненный цикл и, следовательно, getItem больше не вызывается - фрагменты воссоздаются автоматически без предъявителей.

Есть ли известное решение этой проблемы?

4 ответа

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

Как я уже упоминал в одном из комментариев, цель здесь - восстановить ViewPager от процесса уничтожения и в идеале держите инициализацию Presenter отделенной от View. На данный момент мое решение состоит в том, чтобы переопределить restoreState(Parcelable state, ClassLoader loader) внутри FragmentStatePagerAdapter, осмотреть государство Parcelable аналогично фактической реализации restoreState метод, то для каждого фрагмента определенного класса, я могу инициализировать докладчик и назначить ему представление.

@Override
public void restoreState(Parcelable state, ClassLoader loader) {
    if (state != null) {
        Bundle bundle = (Bundle)state;
        bundle.setClassLoader(loader);
        Iterable<String> keys = bundle.keySet();
        for (String key: keys) {
            if (key.startsWith("f")) {
                Fragment f = mFragmentManager.getFragment(bundle, key);
                if (f != null) {
                    if (f instanceof FirstFragment) {
                       new FirstPresenter(repo, (FirstContract.View) f, projectId, userId);
                    }
                } else {
                    Log.w(TAG, ".restoreState() - bad fragment at key " + key);
                }
            }
        }
    }

    super.restoreState(state, loader);
}

Прежде всего, мое решение включает в себя FragmentManager.FragmentLifecycleCallbacks, который является

Интерфейс обратного вызова для прослушивания изменений состояния фрагмента, которые происходят в данном FragmentManager

и придерживается разделения интересов, как я бы сказал, в схеме Android Architecture Blueprints.

  • Activity создает Presenter, проходя вдоль View/ Fragment, чтобы
  • Presenter знает его View и кроме того устанавливает себя его Presenter

В Activity"s onCreate Я регистрирую FragmentLifecycleCallbacks слушатель, позвонив это

private void registerFragmentsLifecycleListener() {

    // All registered callbacks will be automatically unregistered when
    // this FragmentManager is destroyed.
    getSupportFragmentManager.registerFragmentLifecycleCallbacks(
        new FragmentManager.FragmentLifecycleCallbacks() {

            // Called after the fragment has returned from its onActivityCreated
            @Override
            public void onFragmentActivityCreated(FragmentManager fm, Fragment f,
                                                  Bundle savedInstanceState) {

                createPresenter(f);
            }
        }, false); // true to register callback for all child FragmentManagers
}

Слушатель получает уведомление после Fragment вернулся из своего onActivityCreated чтобы убедиться, что только для каждого нового Fragment экземпляр добавлен ViewPager новый Presenter будет создан. Фрагмент может быть прикреплен / отсоединен, его вид может быть создан / уничтожен пару раз, ничего не нужно было делать, но все же получил его Presenter,

Потому что в случае отдыха (например, поочередно) Fragments' onCreate называется до Activityодин (где FragmentLifecycleCallbacks слушатель зарегистрирован!), слушатель не может реализовать onFragmentCreated, должно быть onFragmentActivityCreated,

Для данного нового Fragment Например, мы можем определить, какие Presenter нужно:

private void createPresenter(Fragment fragment) {

    if (fragment instanceof WhateverContract.View) {

        WhateverContract.Presenter whateverPresenter =
            new WhateverPresenter((WhateverContract.View) fragment);

    } else if (...){}
}

Presenter соединяется с его View/Fragment в конструкторе

private final WhateverContract.View mView;

public WhateverPresenter(@NonNull WhateverContract.View view) {

    mView = checkNotNull(view, "view cannot be null!");
    mView.setPresenter(this);
}

а затем может быть запущен в Fragments onResume,


Если что-то не так или улучшается, пожалуйста, дайте мне знать:)

Предложенный ответ не работал для меня с тех пор mFragmentManager является частным членом FragmentStatePagerAdapter, Понятия не имею, как это работает для вкислицинов. Вместо этого я просто позвонил получил родительский класс, чтобы сделать restoreState затем схватил фрагменты с помощью "instantiateItem". Например:

@Override
public void restoreState(Parcelable state, ClassLoader loader) {
    // this will load all the fragments again
    super.restoreState(state, loader);

    // since the fragments are now loaded, instantiate can be used because it just returns them
    MyFragmentClass tab1 = (MyFragmentClass) instantiateItem(null, 0);
    tab1Presenter.setView(tab1);
    tab1.setPresenter(tab1Presenter);

    // then just do the same for the other fragments
    ...
}

Чувствует себя немного хакером, но это работает.

Как упоминалось в комментариях - Presenter должен быть присоединен (и отключен) в методах жизненного цикла Activity/Fragment. Не во внешних классах, потому что только View может подключить-отключить Presenter в соответствующее время. Но хорошей практикой является инициализация Presenter в отдельном классе (или среде внедрения зависимостей), чтобы отделить его от View.

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