【问题标题】:Recovering presenters for the ViewPager fragments (MVP)恢复 ViewPager 片段的演示者 (MVP)
【发布时间】:2017-07-02 14:50:27
【问题描述】:

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

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

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

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

【问题讨论】:

  • 我认为在 android 中,视图创建了 Presenter,只是因为活动/片段的生命周期。所以你应该从 viewpager 中删除对片段本身的初始化
  • 所以管理演示者的生命周期以及片段生命周期
  • 有道理......但是我想看看是否有其他方法可以解决这个问题,将演示者初始化与片段解耦

标签: android mvp android-mvp


【解决方案1】:

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

【讨论】:

  • 公平点。问题仍然存在——当我们谈论 ViewPager 时,如何将初始化的 Presenter 传递给 View。因为我确实希望它们解耦,并且我不喜欢在视图中初始化演示者的想法。我也有点喜欢为演示者分配视图的想法,如github.com/googlesamples/android-architecture 中所述
【解决方案2】:

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

正如我在其中一个 cmets 中提到的,这里的目标是从进程终止中恢复 ViewPager,并在理想情况下保持 Presenter 初始化与视图分离。目前,我的解决方案是在FragmentStatePagerAdapter 中覆盖restoreState(Parcelable state, ClassLoader loader),检查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);
}

【讨论】:

    【解决方案3】:

    建议的答案对我不起作用,因为 mFragmentManagerFragmentStatePagerAdapter 的私人成员。不知道它对 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,但确实有效。

    【讨论】:

      【解决方案4】:

      首先,我的解决方案包括FragmentManager.FragmentLifecycleCallbacks,这是一个

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

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

      • Activity 创建 Presenter,传递 View/ Fragment,这样
      • Presenter 知道它的 View 并设置自己的 Presenter

      ActivityonCreate 中,我通过调用此函数注册了一个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 返回后,侦听器会收到通知,以确保只有ViewPager 添加的每个 Fragment 实例都有一个新的Presenter将被创建。片段可以被附加/分离,它的视图可以被创建/销毁几次,不需要做任何事情,仍然得到它的Presenter

      因为在娱乐的情况下(例如通过旋转)Fragments'onCreateActivitys 之前调用(FragmentLifecycleCallbacks 侦听器已注册!),侦听器无法实现 @ 987654344@,必须是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);
      }
      

      然后可以在FragmentsonResume启动。


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

      【讨论】:

        猜你喜欢
        • 2021-12-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多