2012-09-03 67 views
8

我有一個ViewPager(延伸FragmentPagerAdapter),其中包含兩個Fragments。我需要刷新ListView每個Fragment當我在他們之間滑動。爲此我實現了ViewPager.OnPageChangeListener接口(即onPageScrollStateChanged)。爲了保留對Fragment的引用,我使用了HashTable。我在HashTable存儲引用FragmentsgetItem()方法:FragmentPagerAdapter不會在方向更改上重新創建碎片?

@Override 
     public Fragment getItem(int num) { 
      if (num == 0) { 
       Fragment itemsListFragment = new ItemsListFragment(); 
       mPageReferenceMap.put(num, itemsListFragment); 
       return itemsListFragment; 
      } else { 
       Fragment favsListFragment = new ItemsFavsListFragment(); 
       mPageReferenceMap.put(num, favsListFragment); 
       return favsListFragment; 
      } 
     } 

所以,當我從一個Fragment到另一個刷卡onPageScrollStateChanged觸發,我使用HashTable調用兩個Fragments(刷新)所需的方法:

public void refreshList() { 
     ((ItemsListFragment) mPageReferenceMap.get(0)).refresh(); 
     ((ItemsFavsListFragment) mPageReferenceMap.get(1)).refresh(); 
    } 

一切都很好,直到orientation change事件發生。後它的代碼在refresh()方法,該方法是:

public void refresh() { 
     mAdapter.changeCursor(mDbHelper.getAll()); 
     getListView().setItemChecked(-1, true); // The last row from a exception trace finishes here (my class). 
    } 

導致IllegalStateException

java.lang.IllegalStateException: Content view not yet created 
     at android.support.v4.app.ListFragment.ensureList(ListFragment.java:328) 
     at android.support.v4.app.ListFragment.getListView(ListFragment.java:222) 
     at ebeletskiy.gmail.com.passwords.ui.ItemsFavsListFragment.refresh(ItemsFavsListFragment.java:17) 

假設Content視圖不確實創建我設置boolean變量onActivityCreated()方法true和使用if/else條件是否調用getListView(),其中顯示了成功創建的活動和內容視圖。

然後,我在調試的時候看到FragmentPagerAdapter調用getItem()和它發生的方法orientation change事件發生後沒有被調用。所以看起來像ViewPager持有對舊Fragments的引用。這只是我的假設。

那麼,有什麼辦法可以強制ViewPager再次致電getItem(),所以我可以適當引用當前的Fragments?可能是其他解決方案?非常感謝你。

回答

4

然後我正在調試,看看FragmentPagerAdapter何時調用getItem(),它發生在方向更改事件後不調用該方法。所以看起來像ViewPager持有對舊碎片的引用。

應該自動重新創建片段,就像任何片段在配置更改上一樣。如果您使用setRetainInstance(true),則會出現異常,在這種情況下,它們應該與之前的片段對象相同。

那麼,有什麼辦法強制ViewPager再次調用getItem(),所以我可以使用適當的引用來當前的碎片?

那裏的碎片有什麼問題?

+0

我不在那裏使用'setRetainInstance()'。問題出現在「方向改變」之後彈出的異常。我只是假設舊片段正在使用中,因爲我檢查了兩個都執行'onActivityCreated()'的條件。 – Eugene

+0

@siik:你什麼時候調用這個'refresh()'方法?你什麼時候抽出新創建的片段來填充你的(ick)'Hashtable'? – CommonsWare

+0

我在'onPageScrollStateChanged()'(這是'ViewPager.OnPageChangeListener'接口的實現,即當我在'Fragments'之間滑動時)調用'refresh()'方法。我在'getItem()'類的方法中填充'HashTable',它擴展了'FragmentPagerAdapter' – Eugene

0

我花了一些日子尋找這個問題的解決方案,以及許多個點想通了:

  • 使用替代的FragmentPagerAdapter代替FragmentStatePagerAdapter

  • 使用FragmentStatePagerAdapterFragmentPagerAdapter

  • return POSITION_NONE on getItemPosition覆蓋FragmentPagerAdapter

  • ,如果你需要的碎片

  • 和很多很多很多其他的動態變化,不使用FragmentPagerAdapter ...

在我的應用程序,像Eugene,我自己管理的實例創建片段。我把它保存在一個專門的類中,因此片段永遠不會被釋放,加速我的應用程序(但消耗更多的資源)。

問題是當我旋轉我的平板電腦(和手機)。該片段沒有調用getItem(int),我無法更改它。

我真的花了很多時間,直到真正找到了解決辦法,所以我需要的StackOverflow社區,誰幫助了我很多很多次分享...

這個問題的解決方案,雖然努力工作找到它,很簡單:

參考只要保持FragmentManager在FragmentPagerAdapter的構造延伸:

public class Manager_Pager extends FragmentPagerAdapter { 

    private final FragmentManager mFragmentManager; 
    private final FragmentActivity mContext; 

    public Manager_Pager(FragmentActivity context) { 

     super(context.getSupportFragmentManager()); 

     this.mContext = context; 
     this.mFragmentManager = context.getSupportFragmentManager(); 
    } 

    @Override 
    public int getItemPosition(Object object) { 

// here, check if this fragment is an instance of the 
// ***FragmentClass_of_you_want_be_dynamic*** 

     if (object instanceof FragmentClass_of_you_want_be_dynamic) { 

// if true, remove from ***FragmentManager*** and return ***POSITION_NONE*** 
// to force a call to ***getItem*** 

      mFragmentManager.beginTransaction().remove((Fragment) object).commit(); 
      return POSITION_NONE; 
     } 

     //don't return POSITION_NONE, avoid fragment recreation. 
     return super.getItemPosition(object); 
    } 

    @Override 
    public Fragment getItem(int position) { 


     if (position == MY_DYNAMIC_FRAGMENT_INDEX){ 

      Bundle args = new Bundle(); 
      args.putString("anything", position); 
      args.putString("created_at", ALITEC.Utils.timeToStr()); 

      return Fragment.instantiate(mContext, FragmentClass_of_you_want_be_dynamic.class.getName(), args); 

     }else 

     if (position == OTHER){ 

      //... 

     }else 

     return Fragment.instantiate(mContext, FragmentDefault.class.getName(), null); 

    } 
} 

這就是所有。它會像魅力一樣工作...

+1

它沒有爲我工作getItem永遠不會調用方向更改。 – JosephM

+0

this.mFragmentManager = context.getSupportFragmentManager(); – alijunior

相關問題