Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Referencing Fragments inside ViewPager

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)?

like image 739
Michał Klimczak Avatar asked May 13 '12 18:05

Michał Klimczak


2 Answers

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!

like image 60
Michał Klimczak Avatar answered Sep 20 '22 08:09

Michał Klimczak


Two things:

  1. 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.

  2. You might consider implementing your HashMap so that it holds WeakReference<Fragment>s instead of the Fragments 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 Fragments will allow you to leverage the garbage collector's ability to determine reachability for you, so you don't have to do it yourself.

like image 40
Alex Lockwood Avatar answered Sep 18 '22 08:09

Alex Lockwood