10

我正在尝试重构现有应用程序以使用 MVP 架构。其中一项活动ViewPager包含三个片段。每个片段都与一个演示者链接。准确地说 - 每个演示者在创建时都会被分配一个View可以使用的对象,即一个Fragment. 现在,我在ViewPager's 适配器中创建这些演示者 - 特别是在getItem(int position)方法中。

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

我面临的问题是,如果进程被杀死然后重新启动,ViewPager它有自己的生命周期,因此getItem不会再次被调用 - 片段是自动重新创建的,没有演示者。

这个问题有已知的解决方案吗?

4

4 回答 4

4

由于这个问题仍然没有理想的答案,我认为分享我的临时解决方案可能会很好。

正如我在其中一条评论中提到的,这里的目标是ViewPager从进程终止中恢复,并理想地保持 Presenter 初始化与视图分离。目前,我的解决方案是覆盖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);
}
于 2017-02-15T19:49:26.403 回答
0

首先,我的解决方案FragmentManager.FragmentLifecycleCallbacks包括

用于监听给定 FragmentManager 中发生的片段状态变化的回调接口

并坚持关注点的分离,我想说的是Android Architecture Blueprints中显示的方式。

  • Activity创建Presenter,传递View/ Fragment,这样
  • Presenter知道它View,而且把自己定为它的Presenter

Activity'sonCreate我通过调用这个来注册一个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以确保仅创建由a new添加的每个 Fragment实例。片段可以被附加/分离,它的视图可以被创建/销毁几次,不需要做任何事情,仍然得到它的.ViewPagerPresenterPresenter

因为在娱乐的情况下(例如通过旋转),Fragments'在 sonCreate之前被调用ActivityFragmentLifecycleCallbacks监听器注册的地方!),监听器无法实现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连接ViewFragment

private final WhateverContract.View mView;

public WhateverPresenter(@NonNull WhateverContract.View view) {

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

然后可以在Fragments中启动onResume


如果有什么问题或需要改进,请告诉我:)

于 2017-07-28T07:51:03.823 回答
0

建议的答案对我不起作用,因为mFragmentManager它是FragmentStatePagerAdapter. 不知道它对 vkislicins 是如何工作的。相反,我只是调用了父类,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
    ...
}

感觉有点hacky,但它有效。

于 2017-06-06T11:48:04.550 回答
0

如评论中所述 - Presenter必须在 Activity/Fragment 生命周期方法中附加(和分离)。不在外部类中,因为只有View可以在适当的时间附加-分离Presenter但是在单独的类(或依赖注入框架)中初始化 Presenter以将其与View分离是一种很好的做法。

于 2017-02-15T01:23:39.533 回答