Skip to content Skip to sidebar Skip to footer

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(); } Howe

Solution 1:

* EDIT *

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

FragmentmyFragment= (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) {
    FragmentmyFragment= 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:

publicvoiddestroyItem(View container, int position, Objectobject) {
    super.destroyItem(container, position, object);
    mPageReferenceMap.remove(position);
}

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

intindex= mViewPager.getCurrentItem();
MyAdapteradapter= ((MyAdapter)mViewPager.getAdapter());
MyFragmentfragment= 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.
 */@Overridepublic Object instantiateItem(ViewGroup container, int position) {
    MyFragmentfragment= (MyFragment) super.instantiateItem(container,
            position);
    mPageReferenceMap.put(position, fragment);
    return fragment;
}

Solution 2:

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

Solution 3:

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.

Solution 4:

Solution with storing fragments to a HashMap in your getItem() method does not work if your activity is re-created!

Problem is, default implementation of the FragmentStatePagerAdapter restores fragments directly from the FragmentManager without calling the getItem() method. This means that you'll never get a chance to store a reference to your fragment.

For more info, see source code: FragmentStatePagerAdapter#restoreState.

This basically means that the only way to get a reference to your fragment is by resorting to reflections. This is relatively* safe** in case youre using support library.

Here's how:

@SuppressWarnings("unchecked")public Fragment getFragment(int position) {
        try {
            Field f = FragmentStatePagerAdapter.class.getDeclaredField("mFragments");
            f.setAccessible(true);
            ArrayList<Fragment> fragments = (ArrayList<Fragment>) f.get(this);
            if (fragments.size() > position) {
                return fragments.get(position);
            }
            returnnull;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

relatively* means that its not as dangerous as using reflection on framework classes. Support classes are compiled into your app and there is no way that this code will work on your device but will crash on some other device. You can still potentially break this solution by updating support library to a newer version

safe** its never really safe to use reflections; however you have to resort to this method when a library you're using has design flaws.

Solution 5:

As @Lancelot mentioned, You may just call and cast result to your SuperCoolFragment:

SuperCoolFragmentfrag= (SuperCoolFragment) yourFragmentStatePageAdpater.instantiateItem(null, position); 

Post a Comment for "Android Fragmentstatepageradapter, How To Tag A Fragment To Find It Later"