Retrieve a Fragment from a ViewPager
Asked Answered
A

23

256

I'm using a ViewPager together with a FragmentStatePagerAdapter to host three different fragments:

  • [Fragment1]
  • [Fragment2]
  • [Fragment3]

When I want to get Fragment1 from the ViewPager in the FragmentActivity.

What is the problem, and how do I fix it?

Assiut answered 9/1, 2012 at 7:38 Comment(0)
I
507

The main answer relies on a name being generated by the framework. If that ever changes, then it will no longer work.

What about this solution, overriding instantiateItem() and destroyItem() of your Fragment(State)PagerAdapter:

public class MyPagerAdapter extends FragmentStatePagerAdapter {
    SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();

    public MyPagerAdapter(FragmentManager fm) {
        super(fm);
    }

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

    @Override
    public Fragment getItem(int position) {
        return MyFragment.newInstance(...); 
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment = (Fragment) super.instantiateItem(container, position);
        registeredFragments.put(position, fragment);
        return fragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        registeredFragments.remove(position);
        super.destroyItem(container, position, object);
    }

    public Fragment getRegisteredFragment(int position) {
        return registeredFragments.get(position);
    }
}

This seems to work for me when dealing with Fragments that are available. Fragments that have not yet been instantiated, will return null when calling getRegisteredFragment. But I've been using this mostly to get the current Fragment out of the ViewPager: adapater.getRegisteredFragment(viewPager.getCurrentItem()) and this won't return null.

I'm not aware of any other drawbacks of this solution. If there are any, I'd like to know.

Imeldaimelida answered 7/3, 2013 at 0:52 Comment(26)
This is the best solution I can think of as well. Only suggestion would be to maybe wrap the Fragment in a WeakReference to guarantee you don't prevent a destroyed fragment from being garbage collected? Just seems like the right thing to do...Springwood
What happens when MyPagerAdapter gets destroyed due to lifecycle (ie rotate), won't registerdFragments be lost? Will the Activity/Fragment using MyPagerAdapter have to save it in onSaveInstanceState, and then need to update it with the new FragmentManager ref?Cathodoluminescence
If I'm not mistaken (and you should check this), the getItem method is not called - as you know - but the instantiateItem method is called for every Fragment that is being restored by the framework after a rotation.Imeldaimelida
Yes I have verified that getItem does not get called again on rotate (for any frags that were already created), since the FragmentManager restores the states of the Fragments it holds in the pager. If instantiateItem is called when each Fragment is restored, then this solution is in fact safer and more future proof than mine or the accepted answer. I will consider trying this myself.Cathodoluminescence
I've tried this method and indeed it doesn't return null, but the Fragment. However when I call getView() on the returned Fragment, it returns a view with type NoSaveStateFrameLayout. I want to get access to the layout of Fragment, to the fragment's children. What can I do?Ossuary
@StreetsOfBoston I believe that if instantiateItem is called, so getItem is called too. At least is what I understand from the original code of FragmentStatePagerAdapterCasket
Best solution ever for retrive PagerAdapter fragments, very smart use of SparseArray for memory optimizationCutch
This will break on lifecycle events - see my answer https://mcmap.net/q/57287/-retrieve-a-fragment-from-a-viewpagerBobsled
@Bobsled I doesn't break it. My solution is not using the result from the 'getItem()' call. Instead, it is using the result stored from the 'instantiateItem()' call. And the fragment's lifecycle is not broken, because the stored fragment will be removed from the sparse-array on the 'destroyItem()' call.Imeldaimelida
@StreetsOfBoston of course you are correct :) Most answers on this I have seen were using getItem() which breaks for the reasons in my answer - I shouldve noticed you are using instantiateItem instead. Good stuff +1 :)Bobsled
I implemented the code with SparseArray<WeakReference<Fragment>> and SparceArray.get() method always returned null. If you'll use .valueAt() method all be good!Daredeviltry
registeredFragments will not be restored in FragmentStatePagerAdapter.html#restoreState.Heptad
It won't get restored by itself. However, during fragment restoration, a fragment being restored by the framework will cause the 'instantiateItem to be called for that fragment.Imeldaimelida
I would like to understand under what conditions we can receive null when calling getRegisteredFragment. You said fragments that have not been instantiated, the thing is that I'm receiving some crashes that I'm not able to reproduce and all of them happened when calling at mViewPagerAdapter.getRegisteredFragment(mNumber) and getting a null from that call. Thanks.Standpoint
It depends a bit on the implementation of the associated PagerAdapter. Since Fragments are lazily created and loaded you can never be sure the call to getRegistererdFragment returns a non-null value. Usually, as long as the Fragment has been shown at some point and not destroyed, this method will return a proper Fragment.Imeldaimelida
adapter in fragment not working #31477278Mange
@StreetsOfBoston I keep getting stackoverflow errors because of instantiate item... Do you have any idea what the cause could be for this?Butterfly
0.5 Hoegaarden for the answerer!Unifilar
I still get null pointer exception when I call getView() on the Fragment, why is that?Scavenge
This is the best solution I've come across so far, works with FragmentPagerAdapter too. Its useful if you want to call a fragment method through the activity and to avoid nullpointerexceptions of the fragment variables after orientation change etc.Cotyledon
+1000, spent 2 days to figure out how to work around which Google wont fix! code.google.com/p/android/issues/…Apiece
how to addFragment with this adapter?Indre
This is the same approach as https://mcmap.net/q/57286/-how-to-get-existing-fragments-when-using-fragmentpageradapter . And references to fragments are lost after a recreation not after a rotation but after activity being killed from background.Canal
I've created a gist using this approach: gist.github.com/hardysim/53edbae66d8046b7cd7648061c5f1435. It also features a listener you can subscribe to when the primary fragment (the current page of the ViewPager) changes and a simple getter for the primary fragment.Aby
It will break when fragments are reordered by notifyDataSetChanged(). So position should not be used as key. To workaround put fragments into List then look up them by yourself.Compton
@StreetsOfBoston, i'm having a problem with your solution, can you help me #55446577Lunate
B
85

For grabbing fragments out of a ViewPager there are a lot of answers on here and on other related SO threads / blogs. Everyone I have seen is broken, and they generally seem to fall into one of the two types listed below. There are some other valid solutions if you only want to grab the current fragment, like this other answer on this thread.

If using FragmentPagerAdapter see below. If using FragmentStatePagerAdapter its worth looking at this. Grabbing indexes that are not the current one in a FragmentStateAdapter is not as useful as by the nature of it these will be completely torn down went out of view / out of offScreenLimit bounds.

THE UNHAPPY PATHS

Wrong: Maintain your own internal list of fragments, added to when FragmentPagerAdapter.getItem() is called

  • Usually using a SparseArray or Map
  • Not one of the many examples I have seen accounts for lifecycle events so this solution is fragile. As getItem is only called the first time a page is scrolled to (or obtained if your ViewPager.setOffscreenPageLimit(x) > 0) in the ViewPager, if the hosting Activity / Fragment is killed or restarted then the internal SpaseArray will be wiped out when the custom FragmentPagerActivity is recreated, but behind the scenes the ViewPagers internal fragments will be recreated, and getItem will NOT be called for any of the indexes, so the ability to get a fragment from index will be lost forever. You can account for this by saving out and restoring these fragment references via FragmentManager.getFragment() and putFragment but this starts to get messy IMHO.

Wrong: Construct your own tag id matching what is used under the hood in FragmentPagerAdapter and use this to retrieve the page Fragments from the FragmentManager

  • This is better insomuch as it copes with the losing-fragment-references problem in the first internal-array solution, but as rightly pointed out in the answers above and elsewhere on the net - it feels hacky as its a private method internal to ViewPager that could change at any time or for any OS version.

The method thats recreated for this solution is

private static String makeFragmentName(int viewId, long id) {
    return "android:switcher:" + viewId + ":" + id;
}

A HAPPY PATH: ViewPager.instantiateItem()

A similar approach to getItem() above but non-lifecycle-breaking is to this is to hook into instantiateItem() instead of getItem() as the former will be called everytime that index is created / accessed. See this answer

A HAPPY PATH: Construct your own FragmentViewPager

Construct your own FragmentViewPager class from the source of the latest support lib and change the method used internally to generate the fragment tags. You can replace it with the below. This has the advantage that you know the tag creation will never change and your not relying on a private api / method, which is always dangerous.

/**
 * @param containerViewId the ViewPager this adapter is being supplied to
 * @param id pass in getItemId(position) as this is whats used internally in this class
 * @return the tag used for this pages fragment
 */
public static String makeFragmentName(int containerViewId, long id) {
    return "android:switcher:" + containerViewId + ":" + id;
}

Then as the doc says, when you want to grab a fragment used for an index just call something like this method (which you can put in the custom FragmentPagerAdapter or a subclass) being aware the result may be null if getItem has not yet been called for that page i.e. its not been created yet.

/**
 * @return may return null if the fragment has not been instantiated yet for that position - this depends on if the fragment has been viewed
 * yet OR is a sibling covered by {@link android.support.v4.view.ViewPager#setOffscreenPageLimit(int)}. Can use this to call methods on
 * the current positions fragment.
 */
public @Nullable Fragment getFragmentForPosition(int position)
{
    String tag = makeFragmentName(mViewPager.getId(), getItemId(position));
    Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
    return fragment;
}

This is a simple solution and solves the issues in the other two solutions found everywhere on the web

Bobsled answered 9/7, 2014 at 19:17 Comment(7)
This will work, but it requires copying the ViewPager class into your own source code. Relying on the 'instantiateItem()' and 'destroyItem()' of a ViewPager's pager-adapter will work and will honor the fragments' lifecycles (these 2 methods are called as well when fragments are created from a saved-instance-state). You are correct, that relying on 'getItem()' being called is not a good idea and using private APIs is neither.Imeldaimelida
+1 i agree that is also a solution and have edited above. The only difference is that the above works in one-more use-case that the instantiateItem() which is when you want to access a fragment that has not been visited yet after a lifecycle event has taken place and was visited before the lifecycle event. A small difference I know but its one that led to a subtle bug in my program hence me looking into this.Bobsled
If setOffscreenPageLimit=1 (default), FragmentStatePageAdapter will start to swap fragments in and out of memory as viewpages are accessed. By a call to getItem() a new instance of revisited pages/fragments will then be created. Upon such revisit, is there a way to instruct the system to resume previously created instances, rather than creating a new one?Nuclease
if outside the page limit it will have to create a new one - but passing in the saved state. If wanting to keep the old ones around then you could increase the page limitBobsled
@Bobsled there is no getItemId(pos) inside FragmentStatePagerAdapterTreatment
i get null when i called getFragmentForPosition, also answer above has long description abt theories but not good coding implementation... its hard to understand for viewpager newbies...plz explain where to put above block of codes and how to implement them to get fragment object from view pagerFayalite
The only solution that worked when using Instant Run on Android StudioCynarra
S
70

Add next methods to your FragmentPagerAdapter:

public Fragment getActiveFragment(ViewPager container, int position) {
String name = makeFragmentName(container.getId(), position);
return  mFragmentManager.findFragmentByTag(name);
}

private static String makeFragmentName(int viewId, int index) {
    return "android:switcher:" + viewId + ":" + index;
}

getActiveFragment(0) has to work.

Here is the solution implemented into ViewPager https://gist.github.com/jacek-marchwicki/d6320ba9a910c514424d. If something fail you will see good crash log.

Salters answered 15/2, 2012 at 12:17 Comment(6)
Thanks a lot:) . Through I sovled it in another way which I use a handler to post the fragment. This is not very suitable but it sovled the problem finally. By the way, you are nice:)Assiut
I was using this method, but I believe it stopped working when I moved to API 17 (?). I would recommend another method, and would prefer it if Google simply published an API to retrieve a Fragment from a ViewPager, given its position.Fishing
i have problem whit calling the second fragment, the method create a new oneBrooke
Since some API version makeFragmentName method was changed to private static String makeFragmentName(int viewId, long id) { return "android:switcher:" + viewId + ":" + id; } so getActiveFragment method now should look like this (use getItemId instead of position for second argument) public Fragment getActiveFragment(ViewPager container, int position) { String name = makeFragmentName(container.getId(), getItemId(position)); return mFragmentManager.findFragmentByTag(name); }Mccaskill
It really do work but it's really dangerous cause it relay on inner implementation of the view pager and if google will change the implementation (and they can) bad things gonna happen. I really hope goole will make it available to get the live fragmentHypsography
my answer points out how to make this not reply on a private implementation https://mcmap.net/q/57287/-retrieve-a-fragment-from-a-viewpagerBobsled
A
37

Another simple solution:

    public class MyPagerAdapter extends FragmentPagerAdapter {
        private Fragment mCurrentFragment;

        public Fragment getCurrentFragment() {
            return mCurrentFragment;
        }
//...    
        @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            if (getCurrentFragment() != object) {
                mCurrentFragment = ((Fragment) object);
            }
            super.setPrimaryItem(container, position, object);
        }
    }
Anabelle answered 14/1, 2014 at 0:33 Comment(3)
This seems perfect for my current fragment needs.Vespucci
If all you need to do is get the currently selected Fragment, this is all you need - the method setPrimaryItem is set on attach and also on every updated to the internal set of the Fragment as the current item.Coracle
This sounds like a nice solution but as setPrimaryItem() is called after ViewPager.OnPageChangeListener#onPageSelected() I cannot use it :-(Aby
C
21

I know this has a few answers, but maybe this will help someone. I have used a relatively simple solution when I needed to get a Fragment from my ViewPager. In your Activity or Fragment holding the ViewPager, you can use this code to cycle through every Fragment it holds.

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
    Fragment viewPagerFragment = fragmentPagerAdapter.getItem(i);
    if(viewPagerFragment != null) {
        // Do something with your Fragment
        // Check viewPagerFragment.isResumed() if you intend on interacting with any views.
    }
}
  • If you know the position of your Fragment in the ViewPager, you can just call getItem(knownPosition).

  • If you don't know the position of your Fragment in the ViewPager, you can have your children Fragments implement an interface with a method like getUniqueId(), and use that to differentiate them. Or you can cycle through all Fragments and check the class type, such as if(viewPagerFragment instanceof FragmentClassYouWant)

!!! EDIT !!!

I have discovered that getItem only gets called by a FragmentPagerAdapter when each Fragment needs to be created the first time, after that, it appears the the Fragments are recycled using the FragmentManager. This way, many implementations of FragmentPagerAdapter create new Fragments in getItem. Using my above method, this means we will create new Fragments each time getItem is called as we go through all the items in the FragmentPagerAdapter. Due to this, I have found a better approach, using the FragmentManager to get each Fragment instead (using the accepted answer). This is a more complete solution, and has been working well for me.

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
    String name = makeFragmentName(mViewPager.getId(), i);
    Fragment viewPagerFragment = getChildFragmentManager().findFragmentByTag(name);
    // OR Fragment viewPagerFragment = getFragmentManager().findFragmentByTag(name);
    if(viewPagerFragment != null) {

        // Do something with your Fragment
        if (viewPagerFragment.isResumed()) {
            // Interact with any views/data that must be alive
        }
        else {
            // Flag something for update later, when this viewPagerFragment
            // returns to onResume
        }
    }
}

And you will need this method.

private static String makeFragmentName(int viewId, int position) {
    return "android:switcher:" + viewId + ":" + position;
}
Cathodoluminescence answered 25/1, 2013 at 21:24 Comment(3)
You just findFragmentByTag(), but where could we set the TAG with fragment??Retiring
@vince The ViewPager itself sets those tags. This solution is fragile because it relies on knowing the "hidden" naming convention of the ViewPager. Streets of Boston's answer is a much more comprehensive solution, which I now use in my project (instead of this approach).Cathodoluminescence
This works great! But I removed the "if (viewPagerFragment.isResumed())" conditional because I need to update my ListFragment pages that are off-screen. Then when the user goes back to the ListFragment page, it is all updated with the new data.Dahlia
T
12

For my case, none of the above solutions worked.

However since I am using the Child Fragment Manager in a Fragment, the following was used:

Fragment f = getChildFragmentManager().getFragments().get(viewPager.getCurrentItem());

This will only work if your fragments in the Manager correspond to the viewpager item.

Talithatalk answered 28/10, 2015 at 21:33 Comment(1)
This is the perfect answer to get old fragments from view pager when activity or fragment is recreated.Stewartstewed
D
9

In order to get current Visible fragment from ViewPager. I am using this simple statement and it's working fine.

      public Fragment getFragmentFromViewpager()  
      {
         return ((Fragment) (mAdapter.instantiateItem(mViewPager, mViewPager.getCurrentItem())));
      }
Diggs answered 1/3, 2017 at 10:49 Comment(0)
S
3

I handled it by first making a list of all the fragments (List<Fragment> fragments;) that I was going to use then added them to the pager making it easier to handle the currently viewed fragment.

So:

@Override
onCreate(){
    //initialise the list of fragments
    fragments = new Vector<Fragment>();

    //fill up the list with out fragments
    fragments.add(Fragment.instantiate(this, MainFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, MenuFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, StoresFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, AboutFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, ContactFragment.class.getName()));


    //Set up the pager
    pager = (ViewPager)findViewById(R.id.pager);
    pager.setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager(), fragments));
    pager.setOffscreenPageLimit(4);
}

so then this can be called:

public Fragment getFragment(ViewPager pager){   
    Fragment theFragment = fragments.get(pager.getCurrentItem());
    return theFragment;
}

so then i could chuck it in an if statement that would only run if it was on the correct fragment

Fragment tempFragment = getFragment();
if(tempFragment == MyFragmentNo2.class){
    MyFragmentNo2 theFrag = (MyFragmentNo2) tempFragment;
    //then you can do whatever with the fragment
    theFrag.costomFunction();
}

but thats just my hack and slash approach but it worked for me, I use it do do relevent changes to my currently displayed fragment when the back button is pushed.

Swansea answered 21/8, 2013 at 15:26 Comment(1)
best answer for meNeoteny
P
3

This is based on Steven's answer above. This will return actual instance of the fragment which is already attached to the parent activity.

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
    for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {

        Fragment viewPagerFragment = (Fragment) mViewPager.getAdapter().instantiateItem(mViewPager, i);
        if(viewPagerFragment != null && viewPagerFragment.isAdded()) {

            if (viewPagerFragment instanceof FragmentOne){
                FragmentOne oneFragment = (FragmentOne) viewPagerFragment;
                if (oneFragment != null){
                    oneFragment.update(); // your custom method
                }
            } else if (viewPagerFragment instanceof FragmentTwo){
                FragmentTwo twoFragment = (FragmentTwo) viewPagerFragment;

                if (twoFragment != null){
                    twoFragment.update(); // your custom method
                }
            }
        }
    }
Pish answered 16/12, 2015 at 7:30 Comment(0)
M
2

I couldn't find a simple, clean way to do this. However, the ViewPager widget is just another ViewGroup , which hosts your fragments. The ViewPager has these fragments as immediate children. So you could just iterate over them (using .getChildCount() and .getChildAt() ), and see if the fragment instance that you're looking for is currently loaded into the ViewPager and get a reference to it. E.g. you could use some static unique ID field to tell the fragments apart.

Note that the ViewPager may not have loaded the fragment you're looking for since it's a virtualizing container like ListView.

Mongoloid answered 9/1, 2012 at 7:55 Comment(2)
Thanks for your answering, I retrieve it with the adpter.getItem(); I'm a freshman in Android programming. really appreciate you a lot. Now I can retrieve the ListFragment and I want to add footerView to it,While I do this in my Activity then the logcat print:" java.lang.IllegalStateException: Content view not yet. created".I know why but I have difficulties dealing with it.Assiut
FragmentActivity have onAttachFragment() method, dose this work for ViewPager whit fragment content?Brooke
T
2

FragmentPagerAdapter is the factory of the fragments. To find a fragment based on its position if still in memory use this:

public Fragment findFragmentByPosition(int position) {
    FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter();
    return getSupportFragmentManager().findFragmentByTag(
            "android:switcher:" + getViewPager().getId() + ":"
                    + fragmentPagerAdapter.getItemId(position));
}

Sample code for v4 support api.

Thither answered 18/6, 2013 at 6:30 Comment(1)
It is returning null in onresume(). Any idea why and hoe to fix it?Proceeding
A
2

You don't need to call getItem() or some other method at later stage to get the reference of a Fragment hosted inside ViewPager. If you want to update some data inside Fragment then use this approach: Update ViewPager dynamically?

Key is to set new data inside Adaper and call notifyDataSetChanged() which in turn will call getItemPosition(), passing you a reference of your Fragment and giving you a chance to update it. All other ways require you to keep reference to yourself or some other hack which is not a good solution.

@Override
public int getItemPosition(Object object) {
    if (object instanceof UpdateableFragment) {
        ((UpdateableFragment) object).update(xyzData);
    }
    //don't return POSITION_NONE, avoid fragment recreation. 
    return super.getItemPosition(object);
}
Atween answered 20/11, 2013 at 6:47 Comment(5)
I don't understand here, you need a reference of a Fragment to use getItemPosition(), so you might as well not use getItemPosition, eh?Exhilarant
getItemPosition() is a method in your adapter. You won't call it directly. You have a reference of your adapter so you call adapter.notifyDataSetChanged() which in turn will call getItemPosition() of your adapter by passing reference of your Fragments. You can see a full implementation in action here #19892328Atween
I've read that over, and I still don't get it. You'd still need a direct reference to those fragments in order to make calls against them, right? You mention that as a hack but I don't see an alternative; adapter.getItem(i) is obviously not going to work.Exhilarant
Ok I have updated my answer to clarify more. Of course a reference is needed to update a Fragment but how to get a reference is debate-able. Other solutions get reference from FragmentManager using a string similar to "android:switcher:"+id or returning POSITION_NONE from getItemosition() causing all fragments to recreate themselves.Atween
Thanks, this makes a lot more sense and matches my experience (so I may not be doing something wrong, ha).Exhilarant
M
2

Must extends FragmentPagerAdapter into your ViewPager adapter class.
If you use FragmentStatePagerAdapter then you will not able to find your Fragment by its ID

public static String makeFragmentName(int viewPagerId, int index) {
  return "android:switcher:" + viewPagerId + ":" + index;
}

How to use this method :-

Fragment mFragment = ((FragmentActivity) getContext()).getSupportFragmentManager().findFragmentByTag(
       AppMethodUtils.makeFragmentName(mViewPager.getId(), i)
);
InterestViewFragment newFragment = (InterestViewFragment) mFragment;
Muskogee answered 24/7, 2017 at 9:2 Comment(0)
Y
2

Hey I have answered this question here. Basically, you need to override

public Object instantiateItem(ViewGroup container, int position)

method of FragmentStatePagerAdapter.

Yatzeck answered 25/6, 2018 at 14:31 Comment(0)
T
1

Best solution is to use the extension we created at CodePath called SmartFragmentStatePagerAdapter. Following that guide, this makes retrieving fragments and the currently selected fragment from a ViewPager significantly easier. It also does a better job of managing the memory of the fragments embedded within the adapter.

Taka answered 30/6, 2014 at 5:44 Comment(0)
E
0

The easiest and the most concise way. If all your fragments in ViewPager are of different classes you may retrieve and distinguish them as following:

public class MyActivity extends Activity
{

    @Override
    public void onAttachFragment(Fragment fragment) {
        super.onAttachFragment(fragment);
        if (fragment.getClass() == MyFragment.class) {
            mMyFragment = (MyFragment) fragment;
        }
    }

}
Escadrille answered 28/10, 2014 at 18:3 Comment(1)
This is wrong too, as there are multiple fragments that get attached when you use the ViewPager. there is the current page fragment, and there is one on its left and one on its right. This allows the user to slide between them without having to initialize them only when the user reaches them.Observant
O
0

I implemented this easy with a bit different approach.

My custom FragmentAdapter.getItem method returned not new MyFragment(), but the instance of MyFragment that was created in FragmentAdapter constructor.

In my activity I then got the fragment from the adapter, check if it is instanceOf needed Fragment, then cast and use needed methods.

Overglaze answered 8/9, 2015 at 17:31 Comment(0)
V
0

Create integer resource id in /values/integers.xml

<integer name="page1">1</integer>
<integer name="page2">2</integer>
<integer name="page3">3</integer>

Then in PagerAdapter getItem function:

public Fragment getItem(int position) {

        Fragment fragment = null;

        if (position == 0) {
            fragment = FragmentOne.newInstance();
            mViewPager.setTag(R.integer.page1,fragment);

        }
        else if (position == 1) {

            fragment = FragmentTwo.newInstance();
            mViewPager.setTag(R.integer.page2,fragment);

        } else if (position == 2) {

            fragment = FragmentThree.newInstance();
            mViewPager.setTag(R.integer.page3,fragment);

        }

        return fragment;
        }

Then in activity write this function to get fragment reference:

private Fragment getFragmentByPosition(int position) {
    Fragment fragment = null;

    switch (position) {
        case 0:
            fragment = (Fragment) mViewPager.getTag(R.integer.page1);
            break;

        case 1:

            fragment = (Fragment) mViewPager.getTag(R.integer.page2);
            break;

        case 2:
            fragment = (Fragment) mViewPager.getTag(R.integer.page3);
            break;
            }

            return fragment;
    }

Get the fragment reference by calling the above function and then cast it to your custom fragment:

Fragment fragment = getFragmentByPosition(position);

        if (fragment != null) {
                    FragmentOne fragmentOne = (FragmentOne) fragment;
                    }
Vinnievinnitsa answered 22/2, 2017 at 17:28 Comment(0)
C
0

Easy way to iterate over fragments in fragment manager. Find viewpager, that has section position argument, placed in public static PlaceholderFragment newInstance(int sectionNumber).

public PlaceholderFragment getFragmentByPosition(Integer pos){
    for(Fragment f:getChildFragmentManager().getFragments()){
        if(f.getId()==R.id.viewpager && f.getArguments().getInt("SECTNUM") - 1 == pos) {
            return (PlaceholderFragment) f;
        }
    }
    return null;
}
Cleodal answered 27/2, 2017 at 6:3 Comment(0)
S
0

In Fragment

public int getArgument(){
   return mPage;
{
public void update(){

}

In FragmentActivity

List<Fragment> fragments = getSupportFragmentManager().getFragments();
for(Fragment f:fragments){
    if((f instanceof PageFragment)&&(!f.isDetached())){
          PageFragment pf = (PageFragment)f;   
          if(pf.getArgument()==pager.getCurrentItem())pf.update();
    }
}
Sluggard answered 13/4, 2017 at 12:27 Comment(0)
F
0

in TabLayout there are multiple tab for Fragment. you can find the fragment by Tag using the index of the fragment.

For ex. the index for Fragment1 is 0, so in findFragmentByTag() method, pass the tag for the Viewpager.after using fragmentTransaction you can add,replace the fragment.

String tag = "android:switcher:" + R.id.viewPager + ":" + 0; Fragment1 f = (Fragment1) getSupportFragmentManager().findFragmentByTag(tag);

Flosser answered 19/6, 2018 at 11:4 Comment(0)
A
-1

Ok for the adapter FragmentStatePagerAdapter I fund a solution :

in your FragmentActivity :

ActionBar mActionBar = getSupportActionBar(); 
mActionBar.addTab(mActionBar.newTab().setText("TAB1").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment1.class.getName())));
mActionBar.addTab(mActionBar.newTab().setText("TAB2").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment2.class.getName())));
mActionBar.addTab(mActionBar.newTab().setText("TAB3").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment3.class.getName())));

viewPager = (STViewPager) super.findViewById(R.id.viewpager);
mPagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), mActionBar);
viewPager.setAdapter(this.mPagerAdapter);

and create a methode in your class FragmentActivity - So that method give you access to your Fragment, you just need to give it the position of the fragment you want:

public Fragment getActiveFragment(int position) {
String name = MyPagerAdapter.makeFragmentName(position);
return getSupportFragmentManager().findFragmentByTag(name);
}

in your Adapter :

public class MyPagerAdapter extends FragmentStatePagerAdapter {

private final ActionBar actionBar;
private final FragmentManager fragmentManager;

public MyPagerAdapter(FragmentManager fragmentManager, com.actionbarsherlock.app.ActionBarActionBar mActionBar) {super(fragmentManager);
this.actionBar = mActionBar;
this.fragmentManager = fragmentManager;
}

@Override
public Fragment getItem(int position) {
getSupportFragmentManager().beginTransaction().add(mTchatDetailsFragment, makeFragmentName(position)).commit();
return (Fragment)this.actionBar.getTabAt(position);
}

@Override
public int getCount() {
return this.actionBar.getTabCount();
}

@Override
public CharSequence getPageTitle(int position) {
return this.actionBar.getTabAt(position).getText();
}

private static String makeFragmentName(int viewId, int index) {
return "android:fragment:" + index;
}

}
Antiquity answered 4/4, 2013 at 22:45 Comment(0)
B
-1
Fragment yourFragment = yourviewpageradapter.getItem(int index);

index is the place of fragment in adapter like you added fragment1 first so retreive fragment1 pass index as 0 and so on for rest

Baeza answered 30/6, 2016 at 10:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.