1

I have several fragments which are organized with a ViewPager. I add an addOnPageChangeListener to the ViewPager in MainActivity's onCreate method which gives the position of the selected fragment.

Even though I prevent the fragments from destroying themselves with stating a setOffscreenPageLimit, I still haven't figured out how to access fragments from MainActivity, as simply using findViewById returns null object exceptions.

What I want to do:

I would like to access elements of fragments, e.g. layouts and scrollviews, in the OnPageListener of the ViewPager:

mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

@Override
    public void onPageSelected(int i) {

        if(i == 0) {
            // Do something with the first fragment.
        } else if(i == 1) {
            // Do something with the second fragment.
        }

    }

}

The ViewPager uses a FragmentPagerAdapter:

public class SectionsPagerAdapter extends FragmentPagerAdapter {

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

    @Override
    public Fragment getItem(int position) {

        switch (position) {
            case 0:
                return Fragment1.newInstance(position);
            case 1:
                return Fragment2.newInstance(position);
            case 2:
                return Fragment3.newInstance(position);
            case 3:
                return Fragment4.newInstance(position);
            default:
                throw new IllegalArgumentException();
        }
    }

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

Which is added like this:

mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mSectionsPagerAdapter);

~

Or should I change my approach?

If accessing fragments cannot be achieved with this design, what could be an effective alternative route?

I've tried to implement ViewPager.onPageChangeListener in the custom ViewPager, but it didn't seem to be a good option.

I could deal with the elements in their respective fragments, but this is a tedious process and hard to maintain, which I the reason I look for a way to handle them simultaneously.

I know similar questions have been asked before, but I didn't find a solution in them.

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
Erlend K.H.
  • 448
  • 6
  • 21

1 Answers1

6

Unfortunately the only "safe" way to do it is to check the source code of FragmentPagerAdapter, and see what tag is the fragment is added with - because findFragmentByTag is the only safe way to get a Fragment from a FragmentManager.

Of course, we need to hope that this implementation detail doesn't change between support library versions, but it actually hasn't changed in years :)


Anyways, so FragmentPagerAdapter says:

    // Do we already have this fragment?
    String name = makeFragmentName(container.getId(), itemId);
    Fragment fragment = mFragmentManager.findFragmentByTag(name);

So what is name?

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

What is viewId and what is id?

ViewId is container.getId(), where container is the ViewPager itself.

id is: final long itemId = getItemId(position); which by default is return position;.


So you can find the Fragment as follows:

Fragment fragment = fragmentManager.findFragmentByTag("android:switcher:" + viewPager.getId() + ":" + fragmentPosition);
// if fragment is null, it was not created yet by ViewPager

NOTE:

It is worth noting that you should NOT rely on getItem(int position) { to return the same fragment instance as you passed in, because that will lead you to this problem. (This question does it correctly, the getItem() method must always return a new Fragment instance.)

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
  • 1
    Thank you for the detailed answer. I just tested it inside the `onPageSelected` of the ViewPager's `onPageChangeListener` and it returned the correct fragments. I'll come back to you when I've done some more testing. Right, so next would be to find a view of the selected fragment. – Erlend K.H. Jan 20 '19 at 19:34
  • 1
    It works very well, thank you! Wish I could give a higher reward as it deserves it. – Erlend K.H. Jan 20 '19 at 19:47