Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android FragmentStatePagerAdapter, how to tag a fragment to find it later

When using the FragmentStatePageAdapter I get the fragments like this:

    @Override
    public Fragment getItem(int position) {
        return new SuperCoolFragment();
    }

However, later on my code I need to find this fragment to set a property. In some other parts of the app where I use fragments I basically tag them and look for them using findFragmentByTag(TAG) but with now I don't know how to do it.

How do can I find the fragments using the FragmentStatePageAdapter?

like image 658
Héctor Júdez Sapena Avatar asked Sep 12 '12 09:09

Héctor Júdez Sapena


3 Answers

* EDIT *

As @ElliotM pointed out, there is a better solution. No need to change anything in your adapter, just get the fragment with:

Fragment myFragment = (Fragment) adapter.instantiateItem(viewPager, viewPager.getCurrentItem());

* OLD SOLUTION *

Best option is the second solution here: http://tamsler.blogspot.nl/2011/11/android-viewpager-and-fragments-part-ii.html

In short: you keep track of all the "active" fragment pages. In this case, you keep track of the fragment pages in the FragmentStatePagerAdapter, which is used by the ViewPager..

public Fragment getItem(int index) {
    Fragment myFragment = MyFragment.newInstance();
    mPageReferenceMap.put(index, myFragment);
    return myFragment;
}

To avoid keeping a reference to "inactive" fragment pages, we need to implement the FragmentStatePagerAdapter's destroyItem(...) method:

public void destroyItem(View container, int position, Object object) {
    super.destroyItem(container, position, object);
    mPageReferenceMap.remove(position);
}

... and when you need to access the currently visible page, you then call:

int index = mViewPager.getCurrentItem();
MyAdapter adapter = ((MyAdapter)mViewPager.getAdapter());
MyFragment fragment = adapter.getFragment(index);

... where the MyAdapter's getFragment(int) method looks like this:

public MyFragment getFragment(int key) {
    return mPageReferenceMap.get(key);
}

--- EDIT:

Also add this in your adapter, for after an orientation change:

/**
 * After an orientation change, the fragments are saved in the adapter, and
 * I don't want to double save them: I will retrieve them and put them in my
 * list again here.
 */
@Override
public Object instantiateItem(ViewGroup container, int position) {
    MyFragment fragment = (MyFragment) super.instantiateItem(container,
            position);
    mPageReferenceMap.put(position, fragment);
    return fragment;
}
like image 170
Frank Avatar answered Nov 11 '22 09:11

Frank


I've found another way of doing it, not sure if there would be any issues for using it, it seems ok to me.

I was checking at the code for FragmentStatePageAdapter and I saw this method:

@Override
52     public Object More ...instantiateItem(View container, int position) {
53         // If we already have this item instantiated, there is nothing
54         // to do.  This can happen when we are restoring the entire pager
55         // from its saved state, where the fragment manager has already
56         // taken care of restoring the fragments we previously had instantiated.
57         if (mFragments.size() > position) {
58             Fragment f = mFragments.get(position);
59             if (f != null) {
60                 return f;
61             }
62         }
63 
64         if (mCurTransaction == null) {
65             mCurTransaction = mFragmentManager.beginTransaction();
66         }
67 
68         Fragment fragment = getItem(position);
69         if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
70         if (mSavedState.size() > position) {
71             Fragment.SavedState fss = mSavedState.get(position);
72             if (fss != null) {
73                 fragment.setInitialSavedState(fss);
74             }
75         }
76         while (mFragments.size() <= position) {
77             mFragments.add(null);
78         }
79         fragment.setMenuVisibility(false);
80         mFragments.set(position, fragment);
81         mCurTransaction.add(container.getId(), fragment);
82 
83         return fragment;
84     }

You can use this method to get the fragment already instated for that particular position. So if you want to get Fragment at position 1, you just need to call:

myFragmentStatePageAdpater.instantiateItem(null, 1)

Hope that helps

like image 37
Lancelot Avatar answered Nov 11 '22 10:11

Lancelot


I implemented this by adding a getItemTag(int position) function to FragmentStatePagerAdapter. A drop-in version of the updated file is here if anyone else wants to go this route.

like image 32
Chris Lacy Avatar answered Nov 11 '22 10:11

Chris Lacy