Getting the current Fragment instance in the viewpager
Asked Answered
P

31

241

Below is my code which has 3 Fragment classes each embedded with each of the 3 tabs on ViewPager. I have a menu option. As shown in the onOptionsItemSelected(), by selecting an option, I need to update the fragment that is currently visible. To update that I have to call a method which is in the fragment class. Can someone please suggest how to call that method?

public class MainActivity  extends ActionBarActivity {

     ViewPager ViewPager;
     TabsAdapter TabsAdapter;

     @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            ViewPager = new ViewPager(this);
            ViewPager.setId(R.id.pager);
            setContentView(ViewPager);

            final ActionBar bar = getSupportActionBar();

            bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

            //Attaching the Tabs to the fragment classes and setting the tab title.
            TabsAdapter = new TabsAdapter(this, ViewPager);
            TabsAdapter.addTab(bar.newTab().setText("FragmentClass1"),
                    FragmentClass1.class, null);
            TabsAdapter.addTab(bar.newTab().setText("FragmentClass2"),
              FragmentClass2.class, null);
            TabsAdapter.addTab(bar.newTab().setText("FragmentClass3"),
              FragmentClass3.class, null);


            if (savedInstanceState != null) {
                bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
            }

        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {

            switch (item.getItemId()) {

            case R.id.addText:

           **// Here I need to call the method which exists in the currently visible Fragment class**

                    return true;

            }

            return super.onOptionsItemSelected(item);
        }


     @Override
     protected void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
            outState.putInt("tab", getSupportActionBar().getSelectedNavigationIndex());

     }

     public static class TabsAdapter extends FragmentPagerAdapter
      implements ActionBar.TabListener, ViewPager.OnPageChangeListener {

      private final Context mContext;
            private final ActionBar mActionBar;
            private final ViewPager mViewPager;
            private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();

            static final class TabInfo {
                private final Class<?> clss;
                private final Bundle args;

                TabInfo(Class<?> _class, Bundle _args) {
                    clss = _class;
                    args = _args;
                }
            }

      public TabsAdapter(ActionBarActivity activity, ViewPager pager) {
       super(activity.getSupportFragmentManager());
                mContext = activity;
                mActionBar = activity.getSupportActionBar();
                mViewPager = pager;
                mViewPager.setAdapter(this);
                mViewPager.setOnPageChangeListener(this);
            }

      public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
                TabInfo info = new TabInfo(clss, args);
                tab.setTag(info);
                tab.setTabListener(this);
                mTabs.add(info);
                mActionBar.addTab(tab);
                notifyDataSetChanged();

            }

      @Override
      public void onPageScrollStateChanged(int state) {
       // TODO Auto-generated method stub

      }

      @Override
      public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
       // TODO Auto-generated method stub

      }

      @Override
      public void onPageSelected(int position) {
       // TODO Auto-generated method stub
       mActionBar.setSelectedNavigationItem(position);
      }

      @Override
      public void onTabReselected(Tab tab, FragmentTransaction ft) {
       // TODO Auto-generated method stub

      }

      @Override
      public void onTabSelected(Tab tab, FragmentTransaction ft) {
       Object tag = tab.getTag();
                for (int i=0; i<mTabs.size(); i++) {
                    if (mTabs.get(i) == tag) {
                        mViewPager.setCurrentItem(i);

                    }
                }

                tabPosition = tab.getPosition();
      }

      @Override
      public void onTabUnselected(Tab tab, FragmentTransaction ft) {
       // TODO Auto-generated method stub

      }

      @Override
      public Fragment getItem(int position) {
       TabInfo info = mTabs.get(position);
                return Fragment.instantiate(mContext, info.clss.getName(), info.args);
      }

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

     }

    }

Suppose below is the fragment class with the method updateList() I want to call:

 public class FragmentClass1{

    ArrayList<String> originalData;


    @Override
         public View onCreateView(LayoutInflater inflater, ViewGroup container,
           Bundle savedInstanceState) {

          View fragmentView = inflater.inflate(R.layout.frag1, container, false);

          originalData = getOriginalDataFromDB();

          return fragmentView;

         }


    public void updateList(String text)
    {
       originalData.add(text);
       //Here I could do other UI part that need to added
    }
}
Percheron answered 4/9, 2013 at 8:46 Comment(15)
which method of fragment you want to call?Farra
@BirajZalavadia My own defined method, which has a parameter in it and uses the instance variables of that fragment class which have already been initialized while creating a view even.Percheron
can you give the Class name of Your fragments which are in viewpager?Farra
some solution #7379665Bootle
The simplest way of accessing the visible fragments would be through #7379665 , look at the top two answers.Vollmer
@Yume117 I did see this, but I am unable to get where to use that. Do I need to again find the viewpager by Id though I have reference.Percheron
@Luksprog I saw this. But I have 3 classes here. Do I need to again find the viewpager ? Even I am getting nullpointerexception when I use this as the instance variable, in the above code it's arraylist. Because it seems the object is again being created instead of getting the already associated reference of the fragment.Percheron
This shouldn't be a problem. If you have three types of fragment you know which type belongs to which position in the ViewPager. If FragmentClass1 is the fragment on the first position then if the ViewPager.getCurrentItem() returns 0 it means you need to cast it to FragmentClass1 and call the method.Vollmer
First you should change the name of your viewpager. Generally do not name the variable the same as there type, ViewPager should not be named ViewPager.Bootle
take a look here #18568262Bootle
@Luksprog I did it, but I am getting the same NPE problem for the instance variables of that fragment class. In the question above, for OriginalData arraylist :(Percheron
@rick, does your fragment save application state? i see you're using onSaveInstanceState(Bundle outState) method, because i am having issues saving state..so i was forced to use setOffscreenPageLimit, your reply will be appreciated. thanksSwordcraft
This is the simplest and most reliable solution: https://mcmap.net/q/57531/-getting-the-current-fragment-instance-in-the-viewpagerYeaton
See this answer https://mcmap.net/q/57287/-retrieve-a-fragment-from-a-viewpagerTiti
getSupportFragmentManager().getFragments().get(viewPager.getCurrentItem()); Works just fineMora
V
216

by selecting an option, I need to update the fragment that is currently visible.

A simple way of doing this is using a trick related to the FragmentPagerAdapter implementation:

case R.id.addText:
     Fragment page = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + ViewPager.getCurrentItem());
     // based on the current position you can then cast the page to the correct 
     // class and call the method:
     if (ViewPager.getCurrentItem() == 0 && page != null) {
          ((FragmentClass1)page).updateList("new item");     
     } 
return true;

Please rethink your variable naming convention, using as the variable name the name of the class is very confusing(so no ViewPager ViewPager, use ViewPager mPager for example).

Vollmer answered 4/9, 2013 at 10:9 Comment(18)
Is that fragment tag future-proof, if the API changes?Recto
@Recto No, it's just a common hack that has been used since the adapter appeared(and its source code was available), it hasn't changed yet. If you want something more reliable you'll need to use other options, most notable overriding the instantiateItem() method and getting references to the proper fragments yourself.Vollmer
After hours of frustration and asking the pages directly from the mAdapter.getItem(position), awesome... At least now I know that the other 8512 trials didn't work. ThanksSusie
It is very hard to understand why the FragmentViewPager does not offer a method for accessing the current fragment. Since it is such a basic functionality, is there anyone who knows why they omitted that?Micron
@AntonioSesto That would be a question only the platform engineers could answer. My assumption would be they initially wanted to keep the API very simple and then abandoned the idea as users got over the issue.Vollmer
Well, allowing the access to the current fragment would not be so complicated, but they force us to re-write code that they have hidden in the class and that can potentially break with future updates.Micron
This solution doesn't seem to workout for me....I'm receiving the page =null in my case....Can you please help me out..Clearing
@Clearing Please post a new question with your problem. What I wrote should work unless you're doing something fishy with the id of the ViewPager.Vollmer
Note this does not work if you use FragmentStatePagerAdapter rather than FragmentPagerAdapter.Cymar
@ShawnLauzon The FragmentStatePagerAdapter has a different implementation, in its case you call its instantiateItem() method to get the visible fragments.Vollmer
@Luksprog Yes, you're right. The method names they chose sure are weird. "Instantiate" often instantiates nothing :/Cymar
@ShawnLauzon Thanks! using FragmentPagerAdapter rather than FragmentStatePagerAdapter did it for me!Yeargain
Although i really don't like this fix I will choose this one and use it in my app. It is nasty in the sense that it uses platform knowledge (i.e. the tags used by FragmentPagerAdapter) to provide a solution, but it is a nasty solution to a nasty problem, which sounds quite symmetric. And programmers love symmetry.Devin
what is this condition ViewPager.getCurrentItem() == 0? Shouldn't be ViewPager.getCurrentItem() != 0?Unfortunate
@Unfortunate The FragmentClass1 is used in the adapter in position 0 so we will cast to that fragment only when the current visible item in the adapter is position 0. If we were to use ViewPager.getCurrentItem() != 0 you'll end up with a ClassCastException if the current visible fragment isn't anything besides position 0.Vollmer
Note that this implementation does not work for FragmentStatePagerAdapter. I had to switch to FragmentPagerAdapter. For FragmentStatePagerAdapter the findFragmentByTag("android:switcher:${R.id.myViewPagerId}:${myViewPager.currentItem}") usually returns null.Bother
@Luksprog I wanna do the same thing in Kotlin. I referred to your answer but got page as null.Fonseca
you should never rely on undocumented features of internal code. they are undocumented for a reason.Seel
O
167
    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);
        }
    }
Oneman answered 14/1, 2014 at 0:36 Comment(4)
Google should provide FragmentPageAdapter.getCurrentPrimaryItem() returning mCurrentPrimaryItem.Portingale
I use this technique as well.I also define a PagerFragment with methods onPageSelected / onPageDeselected and have all my pager fragments extend it. Then setPrimaryitem can call these methods appropriately when the user swipes to a new page. This means you may implement a lazier strategy for loading of data in pages that aren't even shown. You should however bear in mind that during page transition it looks better if the next page is already populated with data, so lazy loading all data in onPageSelected may not be ideal.Dandrea
Why the if statement? Fragment just calls up to the equals method of object, which is shallow comparison. So why not just always call mCurrentFragment = ((Fragment) object); ?Giana
tried and it works fine, just cast the getCurrentFragment() to the specific Fragment it shouldGabbey
E
121

First of all 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.

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

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

@Override
public void destroyItem (ViewGroup 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);
}

Hope it may help!

Eyde answered 4/9, 2013 at 9:19 Comment(9)
Can you please explain clearly? Where do I need to keep this FragmentStatePagerAdapter class in my code? BTW I have 3 fragment classes, not single MyFragmentClass.Percheron
Even better if you update mPageReferenceMap in instantiateItem instead of getItem because it also works after orientation change. '@Override public Object instantiateItem(ViewGroup container, int position) { Fragment fragment = (Fragment)Super.instantiateItem(container, position); mPageReferenceMap.put(position, fragment); return fragment; }'Urfa
What type is mPageReferenceMap?Skerrick
Yes, what is mPageReferenceMap?Fant
mPageReferenceMap is a Map<Integer, Fragment>. You can initialize it using *Map<Integer, Fragment> mPageReferenceMap = new HashMap<Integer, Fragment>" -- or your favorite Map<> implementation.Civilized
This answer is really bad! You shouldn't keep the cache of a ViewPager manually since it handle it by itself. The ViewPager decide when fragment should be allocated or not, what to pause and when, keeping a reference on every fragment will add some useless overhead and is not optimized for the memory.Hermosa
Thanks! I guess this solution is not recommendable, but it's the only one that I think works for me. I needed to get the current fragment (using ViewPager.OnPageChangeListener) to update something there, but I also needed to update views of the other "alive" fragments.Boaz
I tried this approach but unfortunately it doesn't work when the activity is recreated. On Android N and later, you can see this when using the multiwindow feature. When your app is open, long hold the 'recents' button (the square one). The activity and fragment are recreated from savedInstanceState, the adapter is recreated (so the mPageReferenceMap is now empty), but getItem is not called again. The map stays empty so adapter.getFragment(index) will crash.Palaeo
Yeah this is unreliable across Activity recreations. Use this answer instead: https://mcmap.net/q/57286/-how-to-get-existing-fragments-when-using-fragmentpageradapterRomie
P
108

This is the only way I don't get NullPointerException for the instance variables of that particular fragment classes. This might be helpful for others who stuck at the same thing. In the onOptionsItemSelected(), I coded the below way:

if(viewPager.getCurrentItem() == 0) {
    FragmentClass1 frag1 = (FragmentClass1)viewPager
                            .getAdapter()
                            .instantiateItem(viewPager, viewPager.getCurrentItem());
    frag1.updateList(text); 
} else if(viewPager.getCurrentItem() == 1) {
    FragmentClass2 frag2 = (FragRecentApps)viewPager
                            .getAdapter()
                            .instantiateItem(viewPager, viewPager.getCurrentItem());
    frag2.updateList(text);
}
Percheron answered 4/9, 2013 at 11:21 Comment(1)
I think this is the most correct answer - align with the design of FragmentStatePagerAdapter without overriding any code. In fact, it should be as simple as a function just return viewPager.getAdapter().instantiateItem(viewPager, viewPager.getCurrentItem()).Pressmark
N
41

FragmentStatePagerAdapter has public method with the name instantiateItem that return your fragment based on specified parameter values, this method has two parameters ViewGroup (ViewPager) and position.

public Object instantiateItem(ViewGroup container, int position);

Used this method to get specified position's fragment,

Fragment fragment = (Fragment) adaper.instantiateItem(mViewPager, position);
Nicholnichola answered 16/3, 2017 at 5:57 Comment(2)
But this doesn't return the current already instantiated fragment, but a new one instead, no? Thus name "instantiate"...Bradway
@Ixx No it does not create a new fragment. I think method name is incorrect here.Recourse
M
16
getSupportFragmentManager().getFragments().get(viewPager.getCurrentItem());

Cast the instance retreived from above line to the fragment you want to work on with. Works perfectly fine.

viewPager

is the pager instance managing the fragments.

Mora answered 8/8, 2018 at 12:21 Comment(3)
This only works if all pages are loaded as Fragment. When there is for example a tablayout with many tabs/pages then not all of them are loaded, so this could raise an indexoutofbounce exception.Journey
@Journey yes that will need a extra workaround code.Mora
@Journey Evgeny's answer below would handle that situation i thinkMora
B
15

I know its too late but I have really simple ways of doing it,

// for fragment at 0 possition

((mFragment) viewPager.getAdapter().instantiateItem(viewPager, 0)).yourMethod();
Bithia answered 13/2, 2017 at 14:14 Comment(0)
V
11

There are a lot of answers here that don't really address the basic fact that there's really NO WAY to do this predictably, and in a way that doesn't result you shooting yourself in the foot at some point in the future.

FragmentStatePagerAdapter is the only class that knows how to reliably access the fragments that are tracked by the FragmentManager - any attempt to try and guess the fragment's id or tag is not reliable, long-term. And attempts to track the instances manually will likely not work well when state is saved/restored, because FragmentStatePagerAdapter may well not call the callbacks when it restores the state.

About the only thing that I've been able to make work is copying the code for FragmentStatePagerAdapter and adding a method that returns the fragment, given a position (mFragments.get(pos)). Note that this method assumes that the fragment is actually available (i.e. it was visible at some point).

If you're particularly adventurous, you can use reflection to access the elements of the private mFragments list, but then we're back to square one (the name of the list is not guaranteed to stay the same).

Vicennial answered 12/6, 2015 at 17:27 Comment(2)
to deal with the "not work well when state is saved/restored", I override the method saveState(). So that the pager does not save any fragment when the activity is paused. it works.Altorilievo
That just adds to the patchwork, without fixing the underlying issue. I'm not arguing that it doesn't work - just that it's not a good implementation.Vicennial
T
7

by selecting an option, I need to update the fragment that is currently visible.

To get a reference to currently visible fragment, assume you have a reference to ViewPager as mPager. Then following steps will get a reference to currentFragment:

  1. PageAdapter adapter = mPager.getAdapter();
  2. int fragmentIndex = mPager.getCurrentItem();
  3. FragmentStatePagerAdapter fspa = (FragmentStatePagerAdapter)adapter;
  4. Fragment currentFragment = fspa.getItem(fragmentIndex);

The only cast used line 3 is valid usually. FragmentStatePagerAdapter is an useful adapter for a ViewPager.

Tishatishri answered 26/7, 2016 at 6:41 Comment(0)
I
7

Best way to do this, just call CallingFragmentName fragment = (CallingFragmentName) viewPager .getAdapter() .instantiateItem(viewPager, viewPager.getCurrentItem()); It will re-instantiate your calling Fragment, so that it will not throw null pointer exception and call any method of that fragment.

Incommensurable answered 23/8, 2018 at 10:35 Comment(0)
C
5

Current Fragment:

This works if you created a project with the fragments tabbar template.

Fragment f = mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());

Note that this works with the default tabbed activity template implementation.

Carat answered 22/1, 2016 at 15:1 Comment(2)
This depends on your implementation of getItem() - it may return a new instance of the fragment, which is probably not what you want.Aliquant
This is how u do it. if you still have the default configuration when you create a tabor with fragments project. none had this solution. so I thought it would help.Carat
F
4

I have used the following:

 int index = vpPager.getCurrentItem();
 MyPagerAdapter adapter = ((MyPagerAdapter)vpPager.getAdapter());
 MyFragment suraVersesFragment = (MyFragment)adapter.getRegisteredFragment(index);
Fant answered 7/2, 2015 at 7:40 Comment(2)
This relies on a custom pager implementation from the answer found here: #8785721Enactment
This is exactly what I was trying to do but without knowing which methods to override, would have wasted hours - thanks!Yeaton
J
4

When we use the viewPager, a good way to access the fragment instance in activity is instantiateItem(viewpager,index). //index- index of fragment of which you want instance.

for example I am accessing the fragment instance of 1 index-

Fragment fragment = (Fragment) viewPageradapter.instantiateItem(viewPager, 1);

if (fragment != null && fragment instanceof MyFragment) {      
 ((MyFragment) fragment).callYourFunction();

}
Janinejanis answered 8/3, 2018 at 9:27 Comment(0)
T
3

In my previous implementation I stored a list of child Fragments to be able to access them later, but this turned out to be a wrong implementation causing huge memory leaks.

I end up using instantiateItem(...) method to get current Fragment:

val currentFragment = adapter?.instantiateItem(viewPager, viewPager.currentItem)

Or to get any other Fragment on position:

val position = 0
val myFirstFragment: MyFragment? = (adapter?.instantiateItem(viewPager, position) as? MyFragment)

From documentation:

Create the page for the given position. The adapter is responsible for adding the view to the container given here, although it only must ensure this is done by the time it returns from finishUpdate(ViewGroup).

Typescript answered 5/11, 2019 at 8:28 Comment(0)
D
2

After reading all comments and answers I am going to explain an optimal solution for this problem. The best option is @rik's solution, so my improvement is based on his.

Instead of having to ask each FragmentClass like

if(FragmentClass1){
   ...
if(FragmentClass2){
   ...
}

Create your own interface, and make your child fragments implement it, something like

public interface MyChildFragment {
    void updateView(int position);
}

Then, you can initiate and update your inner fragments with

Fragment childFragment = (Fragment) mViewPagerDetailsAdapter.instantiateItem(mViewPager,mViewPager.getCurrentItem());

if (childFragment != null) {
   ((MyChildFragment) childFragment).updateView();
}

P.S. Be careful where you put that code, if you call insatiateItem before the system actually creates it the savedInstanceState of your child fragment will be null therefor

public void onCreate(@Nullable Bundle savedInstanceState){
      super(savedInstanceState)
}

Will crash your app.

Good luck

Darwin answered 5/1, 2017 at 20:17 Comment(0)
U
2

FragmentStatePagerAdapter has a private instance variable called mCurrentPrimaryItem of type Fragment. One can only wonder why Android devs did not supplied it with a getter. This variable is instantiated in setPrimaryItem() method. So, override this method in such a way for you to get the reference to this variable. I simply ended up with declaring my own mCurrentPrimaryItem and copying the contents of setPrimaryItem() to my override.

In your implementation of FragmentStatePagerAdapter:

private Fragment mCurrentPrimaryItem = null;

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
    Fragment fragment = (Fragment)object;
    if (fragment != mCurrentPrimaryItem) {
        if (mCurrentPrimaryItem != null) {
            mCurrentPrimaryItem.setMenuVisibility(false);
            mCurrentPrimaryItem.setUserVisibleHint(false);
        }
        if (fragment != null) {
            fragment.setMenuVisibility(true);
            fragment.setUserVisibleHint(true);
        }
        mCurrentPrimaryItem = fragment;
    }
}

public TasksListFragment getCurrentFragment() {
    return (YourFragment) mCurrentPrimaryItem;
}
Underestimate answered 5/5, 2017 at 10:57 Comment(0)
T
2

You can define the PagerAdapter like this then you will able to get any Fragment in ViewPager.

private class PagerAdapter extends FragmentPagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();

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

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

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

    public void addFragment(Fragment fragment) {
        mFragmentList.add(fragment);
    }
}

To get the current Fragment

Fragment currentFragment = mPagerAdapter.getItem(mViewPager.getCurrentItem());
Tiana answered 13/12, 2017 at 9:16 Comment(0)
B
1

I had the same issue and solved it using this code.

MyFragment fragment = (MyFragment) thisActivity.getFragmentManager().findFragmentById(R.id.container);

Just replace the name MyFragment with the name of your fragment and add the id of your fragment container.

Bedclothes answered 7/7, 2015 at 17:32 Comment(0)
C
1

This is more future-proof than the accepted answer:

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {

    /* ------------------------------------------------------------------------------------------ */
    // region Private attributes :

    private Context _context;
    private FragmentManager _fragmentManager;
    private Map<Integer, String> _fragmentsTags = new HashMap<>();

    // endregion
    /* ------------------------------------------------------------------------------------------ */



    /* ------------------------------------------------------------------------------------------ */
    // region Constructor :

    public MyFragmentPagerAdapter(Context context, FragmentManager fragmentManager) {

        super(fragmentManager);

        _context = context;
        _fragmentManager = fragmentManager;
    }

    // endregion
    /* ------------------------------------------------------------------------------------------ */



    /* ------------------------------------------------------------------------------------------ */
    // region FragmentPagerAdapter methods :

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

    @Override
    public Fragment getItem(int position) {

        if(_fragmentsTags.containsKey(position)) {

            return _fragmentManager.findFragmentByTag(_fragmentsTags.get(position));
        }
        else {

            switch (position) {

                case 0 : { return Fragment.instantiate(_context, Tab1Fragment.class.getName()); }
                case 1 : { return Fragment.instantiate(_context, Tab2Fragment.class.getName()); }
            }
        }

        return null;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {

        // Instantiate the fragment and get its tag :
        Fragment result = (Fragment) super.instantiateItem(container, position);
        _fragmentsTags.put(position, result.getTag());

        return result;
    }

    // endregion
    /* ------------------------------------------------------------------------------------------ */
}
Cognoscenti answered 9/5, 2016 at 15:7 Comment(1)
You should use WeakHashMap instead.Urena
T
1

The scenario in question is better served by each Fragment adding its own menu items and directly handling onOptionsItemSelected(), as described in official documentation. It is better to avoid undocumented tricks.

Towel answered 30/6, 2016 at 23:7 Comment(2)
This answer could use more details for how to actually do that. How does adding a menu item solve the ViewPager problem?Chickenhearted
@Chickenhearted ViewPager problem exists if menu events are handled within Activity that hosts fragments and does not exist if the events are handled within the fragment itself. The link shows how a fragment can add its own menu items.Towel
B
1

This is the simplest hack:

fun getCurrentFragment(): Fragment? {
    return if (count == 0) null
    else instantiateItem(view_pager, view_pager.currentItem) as? Fragment
}

(kotlin code)

Just call instantiateItem(viewPager, viewPager.getCurrentItem() and cast it to Fragment. Your item would already be instantiated. To be sure you can add a check for getCount.

Works with both FragmentPagerAdapter and FragmentStatePagerAdapter!

Bung answered 3/3, 2018 at 16:54 Comment(0)
T
1

If your pager is inside a Fragment then use this:

private fun getPagerCurrentFragment(): Fragment? {
    return childFragmentManager.findFragmentByTag("android:switcher:${R.id.myViewPagerId}:${myViewPager.currentItem}")
}

Where R.id.myViewPagerId is the id of your ViewPager inside the xml Layout.

Throckmorton answered 8/3, 2018 at 14:1 Comment(1)
This only works with normal FragmentPageAdapter and not with FragmentStatePageAdapter.Journey
B
1

Based on what he answered @chahat jain :

"When we use the viewPager, a good way to access the fragment instance in activity is instantiateItem(viewpager,index). //index- index of fragment of which you want instance."

If you want to do that in kotlin

val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
                if ( fragment is YourFragmentFragment)
                 {
                    //DO somthign 
                 }

0 to the fragment instance of 0

//=========================================================================// //#############################Example of uses #################################// //=========================================================================//

Here is a complete example to get a losest vision about

here is my veiewPager in the .xml file

   ...
    <android.support.v4.view.ViewPager
                android:id="@+id/mv_viewpager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_margin="5dp"/>
    ...

And the home activity where i insert the tab

...
import kotlinx.android.synthetic.main.movie_tab.*

class HomeActivity : AppCompatActivity() {

    lateinit var  adapter:HomeTabPagerAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
       ...
    }



    override fun onCreateOptionsMenu(menu: Menu) :Boolean{
            ...

        mSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
          ...

            override fun onQueryTextChange(newText: String): Boolean {

                if (mv_viewpager.currentItem  ==0)
                {
                    val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
                    if ( fragment is ListMoviesFragment)
                        fragment.onQueryTextChange(newText)
                }
                else
                {
                    val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 1) as Fragment
                    if ( fragment is ListShowFragment)
                        fragment.onQueryTextChange(newText)
                }
                return true
            }
        })
        return super.onCreateOptionsMenu(menu)
    }
        ...

}
Blender answered 21/6, 2018 at 18:30 Comment(0)
T
0

In my Activity I have:

int currentPage = 0;//start at the first tab
private SparseArray<Fragment> fragments;//list off fragments
viewPager.setOnPageChangeListener(new OnPageChangeListener() {

@Override
public void onPageSelected(int pos) {
        currentPage = pos;//update current page
}

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



@Override
public void onAttachFragment(Fragment fragment) {
    super.onAttachFragment(fragment);
    if(fragment instanceof Fragment1)
        fragments.put(0, fragment);
    if(fragment instanceof Fragment2)
        fragments.put(2, fragment);
    if(fragment instanceof Fragment3)
        fragments.put(3, fragment);
    if(fragment instanceof Fragment4)
        fragments.put(4, fragment);
}

Then I have the following method for getting the current fragment

public Fragment getCurrentFragment() {
    return fragments.get(currentPage);
}
Thenna answered 4/5, 2015 at 8:16 Comment(0)
M
0

Override setPrimaryItem from your FragmentPagerAdapter: the object is the visible fragment:

 @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            if (mCurrentFragment != object) {
                mCurrentFragment = (LeggiCapitoloFragment) object;
            }
            super.setPrimaryItem(container, position, object);
        }
Mytilene answered 5/1, 2017 at 19:39 Comment(0)
P
0

Simply get the current item from pager and then ask your adapter to the fragment of that position.

 int currentItem = viewPager.getCurrentItem();
    Fragment item = mPagerAdapter.getItem(currentItem);
    if (null != item && item.isVisible()) {
       //do whatever want to do with fragment after doing type checking
        return;
    }
Pskov answered 11/1, 2017 at 10:53 Comment(1)
What if getItem creates a new instanceUrena
A
0

To get current fragment - get position in ViewPager at public void onPageSelected(final int position), and then

public PlaceholderFragment getFragmentByPosition(Integer pos){
    for(Fragment f:getChildFragmentManager().getFragments()){
        if(f.getId()==R.viewpager && f.getArguments().getInt("SECTNUM") - 1 == pos) {
            return (PlaceholderFragment) f;
        }
    }
    return null;
}

SECTNUM - position argument assigned in public static PlaceholderFragment newInstance(int sectionNumber); of Fragment

getChildFragmentManager() or getFragmentManager() - depends on how created SectionsPagerAdapter

Augustina answered 27/2, 2017 at 6:15 Comment(0)
D
0

You can implement a BroadcastReceiver in the Fragment and send an Intent from anywhere. The fragment's receiver can listen for the specific action and invoke the instance's method.

One caveat is making sure the View component is already instantiated and (and for some operations, such as scrolling a list, the ListView must already be rendered).

Decalescence answered 22/2, 2018 at 22:33 Comment(0)
C
0

You can declare an Array of fragment as register fragments

class DashboardPagerAdapter(fm: FragmentManager?) : FragmentStatePagerAdapter(fm!!) {
    // CURRENT FRAGMENT
    val registeredFragments = SparseArray<Fragment>()

    override fun instantiateItem(container: ViewGroup, position: Int): Any {
        val fragment = super.instantiateItem(container, position) as Fragment
        registeredFragments.put(position, fragment)
        return fragment
    }

    override fun getItem(position: Int): Fragment {
        return when (position) {
            0 -> HomeFragment.newInstance()
            1 -> ConverterDashboardFragment.newInstance()
            2 -> CartFragment.newInstance()
            3 -> CustomerSupportFragment.newInstance()
            4 -> ProfileFragment.newInstance()
            else -> ProfileFragment.newInstance()
        }
    }

    override fun getCount(): Int {
        return 5
    }

}

Then you can use it as

adapter?.let {
    val cartFragment = it.registeredFragments[2] as CartFragment?
    cartFragment?.myCartApi(true)
}
Callboy answered 22/1, 2020 at 9:24 Comment(3)
If you decide to go that way, you should also implement destroyItem() and remove the destroyed instance from registeredFragments, other wise you'll have a memory leak.End
That's good advice. You are welcome to make an edit in the answer.Callboy
#55729219 check this outPreparedness
L
0

I tried the following:

 int index = mViewPager.getCurrentItem();
 List<Fragment> fragments = getSupportFragmentManager().getFragments();
 View rootView = fragments.get(index).getView();
Leung answered 19/7, 2020 at 16:39 Comment(0)
A
-1

Because FragmentStateAdapter will add new Fragment to FragmentManager will refer to Fragment in FragmentManager instead of creating new when screen rotates, so you just need to get in FragmentManager good for performance

public MyFragment getActiveFragment() {
        List<Fragment> fragments = getSupportFragmentManager().getFragments();
        for (Fragment fragment : fragments){
            if(fragment instanceof  MyFragment){
                return (MyFragment) fragment;
            }
        }
        return null;
    }
Autochthon answered 26/5, 2021 at 10:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.