I have a problem with referencing my Fragments inside a ViewPager. I would like to do it because from my activity I'd like to refresh a fragment at a specified position (e.g. currently displayed fragment).
Currently I have something like this:
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);
}
}
The problem is that the destroyItem()
gets called more often than getItem()
, so I'm left with null references. If I don't use destroyItem()
to clear references to destroyed fragments... well I reference fragments that don't exist.
Is there any nice way to reference fragments that are created with EventListFragment mFragment = EventListFragment.newInstance(dateOffset);
? Or what should I do to refresh a fragment inside a ViewPager from my activity (from options menu to be precise)?
I managed to solve it. The trick was to make a reference list inside Activity, not PagerAdapter. It goes like this:
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;
}
Of course your fragment has to implement a getPosition()
function, but I needed something like this anyway, so it wasn't a problem.
Thanks Alex Lockwood for your suggestion with WeakReference
!
Two things:
Add the following line in your Activity's onCreate
method (or wherever you initialize your ViewPager):
mPager.setOffscreenPageLimit(NUM_ITEMS-1);
This will keep the additional off-screen pages in memory (i.e. preventing them from being destroyed), even when they aren't currently being shown on the screen.
You might consider implementing your HashMap
so that it holds WeakReference<Fragment>
s instead of the Fragment
s themselves. Note that this would require you to change your getFragment
method as follows:
WeakReference<Fragment> weakRef = mPageReferenceMap.get(position);
return (weakRef != null) ? weakRef.get() : null;
This has nothing to do with your problem... it's just something I noticed and thought I would bring to your attention. Keeping WeakReferences
to your Fragment
s will allow you to leverage the garbage collector's ability to determine reachability for you, so you don't have to do it yourself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With