2017-02-14 76 views
6

我试图重构现有应用程序以使用MVP体系结构。其中一项活动有ViewPager三个片段。每个片段都与演示者链接。准确地说 - 每个演示者在创建时都会得到一个View来处理,即Fragment。现在,我在ViewPager的适配器内创建这些演示者 - 特别是在getItem(int position)方法中。恢复ViewPager片段的演示者(MVP)

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

我现在面临的问题是,如果该进程被终止,然后重新启动,ViewPager都有自己的生命周期,因此getItem不再调用 - 的片段,没有主持人自动地重新创建。

是否有解决此问题的已知解决方案?

+1

我想在android系统视图创建因为活动/片段的生命周期只是演示。所以你应该从viewpager中移除初始化到片段本身 –

+0

所以管理演示者的生命周期以及片段生命周期 –

+0

有道理......但是我想看看是否还有其他方法来解耦演示者初始化从片段 – vkislicins

回答

0

正如评论中所述 - 演示者必须在活动/片段生命周期方法中附加(和分离)。不在外部类别中,因为只有查看可以在适当的时间设置附加 - 取消演示者这是一个很好的做法,用来初始化主持人在单独的类(或依赖注入框架)查看脱钩了。

+0

公平点。问题仍然存在 - 当我们谈论ViewPager时,如何将初始化的Presenter传递给视图。因为我确实希望它们分离,我不喜欢在视图内初始化主持人的想法。此外,我有点像主持人被分配一个视图的想法,如https://github.com/googlesamples/android-architecture – vkislicins

1

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

正如我在其中一个评论中提到的,此处的目标是从进程kill中恢复ViewPager,并理想地保持Presenter初始化与View无关。目前,我的解决方案是覆盖FragmentStatePagerAdapter中的restoreState(Parcelable state, ClassLoader loader),检查类似于restoreState方法的实际实现的状态Parcelable,然后对于某个类的每个片段,我可以初始化演示者并为其分配一个视图。

@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); 
} 
0

建议的答案并没有为我因为工作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 
    ... 
} 

感觉有点哈克,但它的工作原理。

0

首先,我的解决方案包括: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回到了确保,只有由ViewPagerPresenter每添加一个新的Fragment实例将被创建。片段可以被连接/分离,它的视图可以被创建/销毁几次,不需要做任何事情,仍然得到它的Presenter

因为在娱乐的情况下(例如通过旋转)Fragment S'onCreateActivity■一个叫之前(其中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连接在构造

private final WhateverContract.View mView; 

public WhateverPresenter(@NonNull WhateverContract.View view) { 

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

View/Fragment,然后可以在开始Fragment s onResume


如果有什么问题或改进,请让我知道:)