Is it possible to access the current Fragment being viewed by a ViewPager?

AndroidAndroid FragmentsAndroid Viewpager

Android Problem Overview


I have an app with a ViewPager and three Fragments. I'm trying to figure out how to get the current Fragment being viewed so I can get at its arguments.

I have an OnPageChangeListener grabbing the current page index, but

ViewPager.getChildAt(int position);

returns a View. What's the relationship between this View and the current Fragment?

Android Solutions


Solution 1 - Android

I finally found an answer that worked for me. Basically, you can access the fragment for a viewPager page by using the tag "android:switcher:"+R.id.viewpager+":0".

Solution 2 - Android

I've solved this problem the other way round. Instead of searching for the fragment from the activity, I'm registering the Fragment during it's onAttach() method at it's owner activity and de-registering it in the onStop() method. Basic Idea:

Fragment:

@Override
public void onAttach(Activity activity) {
	super.onAttach(activity);
	try{
		mActivity = (IMyActivity)activity;
	}catch(ClassCastException e){
		throw new ClassCastException(activity.toString() +" must be a IMyActivity");
	}
	
	mActivity.addFragment(this);
}

@Override
public void onStop() {
	mActivity.removeFragment(this);
	super.onStop();
}

IMyActivity:

public interface IFriendActivity {
    public void addFragment(Fragment f);
    public void removeFragment(Fragment f);	
}

MyActivity:

public class MyActivity implements IMyActivity{

    [...]

    @Override
    public void addFragment(Fragment f) {
        mFragments.add(f);
    }

    @Override
    public void removeFragment(Fragment f) {
        mFragments.remove(f);
    }

}

Solution 3 - Android

Edit - Don't do this. If you're tempted to, read the comments for why it's a bad idea.

On the odd-chance you're still trying to solve this problem:

Extend FragmentPagerAdapter. In the constructor, build the Fragments you need and store them in a List (array/ArrayList) of Fragments.

private final int numItems = 3;
Fragment[] frags;
	
public SwipeAdapter (FragmentManager fm) {
	super(fm);
	
	//Instantiate the Fragments
	frags = new Fragment[numItems];
		
	Bundle args = new Bundle();
	args.putString("arg1", "foo");
	
	frags[0] = new MyFragment();
	frags[1] = new YourFragment();
	frags[2] = new OurFragment();
	frags[2].setArguments(args);
}

Then for getItem(int position), you can do something like

public Fragment getItem(int position) {
	return frags[position];
}

I'm not sure if this is the generally accepted way of doing it but it worked for me.

Edit

This is really not a good way to go. If you plan on handling orientation changes or your app going into the background, then this will probably break your code. Please read the comments below this answer for more info. Rather use @James 's answer

Solution 4 - Android

Yes, it's possible if you are using FragmentStatePagerAdapter.

ViewPager vp;
//...
YourFragment fragment = (YourFragment) adapter.instantiateItem(vp, vp.getCurrentItem());

Solution 5 - Android

PLEASE DON'T USE THIS

Make your adapter extend the following FragmentStatePagerWithCurrentAdapter class and instead of implementing getItem implement the same code into getItemAtIndex

Set the ViewPager OnPageChangeListener, to the instance of the adapter.

When you need to access the current Fragment you just call adapter.getCurrentItem().

package your.package;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.SparseArray;
import android.view.ViewGroup;

public abstract class FragmentStatePagerWithCurrentAdapter 
extends FragmentStatePagerAdapter 
implements OnPageChangeListener {
	int currentPage = 0;
	
	private SparseArray<Fragment> mPageReferenceMap = new SparseArray<Fragment>();
	
	public FragmentStatePagerWithCurrentAdapter(FragmentManager fm) {
		super(fm);
	}
	
	@Override
	public final Fragment getItem(int index) {
		Fragment myFragment = getItemAtIndex(index);
	    mPageReferenceMap.put(index, myFragment);
	    return myFragment;
	}
	
	public abstract Fragment getItemAtIndex(int index);
	
	@Override
	public void destroyItem(ViewGroup container, int position, Object object) {
	
		super.destroyItem(container, position, object);
		
		mPageReferenceMap.remove(Integer.valueOf(position));
	}
	
	public Fragment getCurrentItem() {
		return mPageReferenceMap.get(currentPage);
	}

	@Override
	public void onPageScrollStateChanged(int arg0) {
		
	}

	@Override
	public void onPageScrolled(int arg0, float arg1, int arg2) {
			
	}

	@Override
	public void onPageSelected(int newPageIndex) {
		currentPage = newPageIndex;
	}
	
}

I used as reference the following blog post: http://tamsler.blogspot.com/2011/11/android-viewpager-and-fragments-part-ii.html

Solution 6 - Android

It's been explained here : http://developer.android.com/guide/topics/fundamentals/fragments.html

In OnCreateView you must return a view to draw a UI for your fragment, I think that's the relationship.

Also this question might be similar: https://stackoverflow.com/questions/6807262/get-focused-view-from-viewpager

Solution 7 - Android

You can do so:

  • On the class extent of a view pager adapter (such as PagerAdapter , FragmentStatePagerAdapter...) override method instantiateItem :

    @Override public Object instantiateItem(ViewGroup container, int position) { final Fragment frag = (Fragment) super.instantiateItem(container, position); if(frag instanceof ListNoteOfTypeFragment){
    final ListNoteOfTypeFragment listNoteOfTypeFragment = (ListNoteOfTypeFragment) frag; //do whatever you want with your fragment here listNoteOfTypeFragment.setNoteChangeListener(mListener); } return frag; }

Solution 8 - Android

Definitive answer that works seamlessly (but small hack):

somewhere in page fragment's layout:

<FrameLayout android:layout_width="0dp" android:layout_height="0dp" android:visibility="gone" android:id="@+id/fragment_reference">
     <View android:layout_width="0dp" android:layout_height="0dp" android:visibility="gone"/>
</FrameLayout>

in fragment's onCreateView():

...
View root = inflater.inflate(R.layout.fragment_page, container, false);
ViewGroup ref = (ViewGroup)root.findViewById(R.id.fragment_reference);
ref.setTag(this);
ref.getChildAt(0).setTag("fragment:" + pageIndex);
return root;

and method to return Fragment from ViewPager, if exists:

public Fragment getFragment(int pageIndex) {		
		View w = mViewPager.findViewWithTag("fragment:" + pageIndex);
		if (w == null) return null;
		View r = (View) w.getParent();
		return (Fragment) r.getTag();
}

Solution 9 - Android

Jorge Garcia's FragmentStatePagerWithCurrentAdapter is a very good solution but it needs a minor improvement. In case the activity gets destroyed and re-created in response to a configuration change or something like that the getItem will not be called for the fragments that were saved and retrieved by the fragment manager. So I override getItem normally in my subclass and I put the following in the FragmentStatePagerWithCurrentAdapter

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Object item = super.instantiateItem(container, position);
    if ( item instanceof Fragment ) {
        pageReferenceMap.put(position, (Fragment)item);
    }
    return item;
}

The instantiateItem is called every time the fragment in that position is accessed.

Solution 10 - Android

Or just save all Fragments in a map:

public class MyFragment extends Fragment implements OnPageChangeListener {

	private ViewPager viewPager;
	private FragmentStatePagerAdapter viewAdapter;
	private View rootView;
	private Map<Integer, Fragment> fragments = new HashMap<Integer, Fragment>();
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		
		rootView = inflater.inflate(R.layout.introdution, container, false);
		
		viewPager = (ViewPager) rootView.findViewById(R.id.pager);
		viewAdapter = new ViewAdapter(getFragmentManager());
		viewPager.setAdapter(viewAdapter);
		viewPager.addOnPageChangeListener(this);
		
		return rootView;
		
	}
	
	private class ViewAdapter extends FragmentStatePagerAdapter {

		public ViewAdapter(FragmentManager fragmentManager) {
			super(fragmentManager);
		}

		@Override
		public Fragment getItem(int position) {
			
			Fragment result = null;
			
			switch (position) {
            	case 0: result = Fragment1.newInstance(); break;
            	case 1: result = Fragment2.newInstance(); break;
			}
			
			if (result != null)
				fragments.put(position, result);
		
			return result;
            	
		}

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

	@Override
	public void onPageScrollStateChanged(int arg0) {
	}

	@Override
	public void onPageScrolled(int arg0, float arg1, int arg2) {
	}
	
	@Override
	public void onPageSelected(int position) {
	
		Fragment currentFragment = fragments.get(position);
	
	}

}

Solution 11 - Android

I think there is the better way by using this

Log.i(TAG, "getCurrentItem " + mViewPager.getCurrentItem());

Can get the current display fragment page.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMitchellSaladView Question on Stackoverflow
Solution 1 - AndroidJamesView Answer on Stackoverflow
Solution 2 - AndroidsdlView Answer on Stackoverflow
Solution 3 - AndroidMike TView Answer on Stackoverflow
Solution 4 - AndroidVolodymyr KulykView Answer on Stackoverflow
Solution 5 - AndroidJorge GarciaView Answer on Stackoverflow
Solution 6 - AndroidDanteView Answer on Stackoverflow
Solution 7 - AndroidAnh NguyenView Answer on Stackoverflow
Solution 8 - AndroidHoxView Answer on Stackoverflow
Solution 9 - AndroiddmaprView Answer on Stackoverflow
Solution 10 - AndroidalmisoftView Answer on Stackoverflow
Solution 11 - AndroidHuy TowerView Answer on Stackoverflow