2012-05-13 86 views
9

我在ViewPager中引用我的片段时遇到问题。我想这样做是因为从我的活动中,我想刷新指定位置的片段(例如,当前显示的片段)。在ViewPager中引用片段

目前,我有这样的事情:

public static class MyPagerAdapter extends FragmentPagerAdapter { 

    private static final String TAG = "MyPagerAdapter"; 
    private static HashMap<Integer, EventListFragment> mPageReferenceMap = new HashMap<Integer, EventListFragment>(); 

    public MyPagerAdapter(FragmentManager fm) { 
     super(fm); 
    } 

    @Override 
    public int getCount() { 
     return NUM_ITEMS; 
    } 

    @Override 
    public Fragment getItem(int position) { 
     Log.i(TAG, "getItem: "+position); 
     int dateOffset = position-1; 
     EventListFragment mFragment = EventListFragment.newInstance(dateOffset); 
     mPageReferenceMap.put(position, mFragment); 
     return mFragment; 
    } 

    @Override 
    public void destroyItem(ViewGroup container, int position, Object object) { 
     Log.i(TAG, "destroyItem: "+position); 
     mPageReferenceMap.remove(position); 
     super.destroyItem(container, position, object); 
    } 


    public EventListFragment getFragment(int key) { 
     Log.i(TAG, "Size of pager references: "+mPageReferenceMap.size()); 
     return mPageReferenceMap.get(key); 
    } 
} 

的问题是,destroyItem()被调用往往比getItem(),所以我留下的空引用。如果我不使用destroyItem()清除对被破坏片段的引用......以及我引用不存在的片段。

有没有什么好的方法可以用EventListFragment mFragment = EventListFragment.newInstance(dateOffset);创建片段?或者我该怎么做才能从我的活动(从选项菜单中精确地)刷新ViewPager中的片段?

回答

5

我设法解决它。诀窍是在Activity中创建引用列表,而不是PagerAdapter。它是这样的:

List<WeakReference<EventListFragment>> fragList = new ArrayList<WeakReference<EventListFragment>>(); 

@Override 
public void onAttachFragment (Fragment fragment) { 
    Log.i(TAG, "onAttachFragment: "+fragment); 
    if(fragment.getClass()==EventListFragment.class){ 
     fragList.add(new WeakReference<EventListFragment>((EventListFragment)fragment)); 
    } 
} 
public EventListFragment getFragmentByPosition(int position) { 

    EventListFragment ret = null; 
    for(WeakReference<EventListFragment> ref : fragList) { 
     EventListFragment f = ref.get(); 
     if(f != null) { 
      if(f.getPosition()==position){ 
       ret = f; 
      } 
     } else { //delete from list 
      fragList.remove(f); 
     } 
    } 
    return ret; 

} 

当然你的片段具有实现getPosition()功能,但我需要这样的事情,无论如何,所以它不是一个问题。

感谢Alex Lockwood对WeakReference的建议!

+0

我刚刚完成了我的决赛,并决定回来看看你是否有事情工作......很高兴我能够帮助(即使它不是主要问题:P)。 –

+0

问题:不应该将fragList.remove()调用传递给弱引用,而不是片段? – gcl1

+0

@Michael:我开始使用这样的方法,它运作得非常好。但由于fragList包含弱引用,因此似乎这些条目会被垃圾回收处理,尽管您仍然需要它们。我看到getFragmentByPosition()方法有时会返回null,所以我认为这就是发生了什么。任何想法如何解决这个问题?谢谢。 – gcl1

3

两件事情:

  1. 添加下面一行在你活动的onCreate方法(或任何你初始化你ViewPager):

    mPager.setOffscreenPageLimit(NUM_ITEMS-1); 
    

    这将保持在内存中的额外离屏页面(即防止它们被破坏),即使它们当前没有显示在屏幕上。

  2. 您可能会考虑实施您的HashMap,以便它自己保留WeakReference<Fragment>而不是Fragment。请注意,这将要求您更改getFragment方法如下:

    WeakReference<Fragment> weakRef = mPageReferenceMap.get(position); 
    return (weakRef != null) ? weakRef.get() : null; 
    

    这无关你的问题......这只是我注意到了,以为我会提请你注意。将WeakReferences保留到Fragment将允许您利用垃圾收集器为您确定可达性的能力,因此您不必亲自操作。

+0

至于2. =>它不会解决我的问题,但可能是一个好主意,以防止泄漏,谢谢。并且1. =>我会有7页,以后可能会更多,可以同时将它们全部保存在内存中吗? –

+0

嗯......显然,你在记忆中留下的'碎片'越少越好。如果你想从'Activity'中按需访问'Fragment'(而不是实际切换到Fragment的页面)而不是将它们全部保存在内存中,修复将变得更加棘手。它可能需要深入研究'ViewPager'源代码并了解它如何处理'Fragment'生命周期。我不知道有什么办法可以做到这一点,但当我有更多时间时我会研究它。 –

+0

我可以谦虚地暗示,如果在屏幕外有任何你需要从片段中获得的东西,也许你不应该把它放在片段上。考虑将其放入Service或ContentProvider中,并让您的Fragment成为它的客户端。 – Sparky