2017-02-14 101 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


如果有什麼問題或改進,請讓我知道:)