ViewPager with fragments - onPause(), onResume()?

徘徊边缘 提交于 2019-11-27 11:18:48

The ViewPager comes with the OnPageChangeListener interface. By setting some flags for the previous and currently shown pages, you can emulate this behavior.

Considering previous solutions are not very clear, here is how I solved it thanks to Phix for his hint:

In the OnPageChange() callback:

    Fragment old_fragment = getActiveFragment(old_position);
    Fragment new_fragment = getActiveFragment(new_position);
    old_f.setUserVisibleHint(false);
    old_f.onPause();
    new_f.setUserVisibleHint(true);
    new_f.onResume();

Then in onResume():

    if (getUserVisibleHint())
        /* resume code */

and in onPause():

    if (!getUserVisibleHint())
        /* pause code */

Here is the getActiveFragment code, avoiding to search for that too:

    return fragmentManager.findFragmentByTag("android:switcher:" + viewPagerId + ":" + position);

NB: Fragment have a isVisible() method, but it doesn't seem to be very consistent, hence the use of UserVisibleHint.

EDIT: Replace the UserVisibleHint by a private flag. Worked much better!

If U are using Android Support Library (rev 11), you can use getUserVisibleHint() or override setUserVisibleHint() to capture the changes visible and hide. Look This post.

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) {
        // do something when visible.
    }
}

Solution 1:

Define a SparseArray in your ViewPagers' adapters like below. In this array we'll hold the instance of fragments.

SparseArray<Fragment> registeredFragments = new SparseArray<>();

And Override your Adapters' instantiateItem method.

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

Also Override destroyItem method of your ViewPagers

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

And define a new method to get your ViewPager Fragments instance.

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

Now you can implement your logic with ViewPager's OnPageChangeListener. Here's an example about how you can implement a viewpager's onPageChangeListener:

Define an integer to keep current position:

int currentPos;

yourViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                // Empty method
            }

            @Override
            public void onPageSelected(int position) {
                  // This is paused fragment.
                  final Fragment pausedFragment = yourAdapter.getRegisteredFragment(currentPos);

                  // update current position value
                  currentPos = position;

                  // This is resumed fragment
                  final Fragment resumedFragment = yourAdapter.getRegisteredFragment(currentPos);
            }

            @Override
            public void onPageScrollStateChanged(int state) {
                // Empty method
            }
        });

Finally for restoring instance state update your current position to keep updated in which position user left ViewPager

currentPos = yourViewPager.getCurrentItem();

Solution 2:

For another solution you can find your ViewPager Fragments by Tag. You can generate your tag with:

@NonNull
public static String generateViewPagerFragmentTag(int viewPagerId, int position) {
        final StringBuilder tagBuilder = new StringBuilder();
        tagBuilder.append("android:switcher:");
        tagBuilder.append(viewPagerId);
        tagBuilder.append(":");
        tagBuilder.append(position);
        return tagBuilder.toString();
    }

And find your Fragment:

final Fragment yourFragment = getSupportFragmentManager().findFragmentByTag(generateViewPagerFragmentTag(R.id.your_viewpager, currentPos));

Edit: A few years ago while i was looking a solution for getting ViewPager's current item i tried UserVisibleHint in Fragments and noticed that it was not reliable. I'm not sure if it's reliable or not now but still i avoid to use.

tainy

You can use below method in Fragment

public void setUserVisibleHint(boolean isVisibleToUser){

}

when isVisibleToUser == true, the fragment is shown

A bit late to the party but in my current app I've set the OffScreenPageLimit to 1 for my viewpager, this means the fragments are not cached and each time the view changes it reloads the current fragment

https://developer.android.com/reference/android/support/v4/view/ViewPager.html#getOffscreenPageLimit()

suomi35

To give a bit more definition to the methods in savepopulation's answer:

yourPager.setOnPageChangeListener(new GridViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int row, int column, float rowOffset, float columnOffset, int rowOffsetPixels, int columnOffsetPixels) {

        }

        @Override
        public void onPageSelected(int row, int column) {
            // When on page selected if position is not specific for you
            // you can find your fragment or you can switch position.
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!