I have a ViewPager that loads three pages at a time. If I swipe from page 1 to page 2 then to 3, the first page(fragment) goes to onPause()
. Then, if I swipe to the second page, 1st page comes to onResume()
even though the page 1 is still not visible to the user. So, my question is: how to distinguish between the first and second page in code? For example, if I have to run a piece of code when the fragment is visible, how is that done?

- 2,249
- 3
- 21
- 31

- 2,166
- 3
- 18
- 30
-
2check out my answer here http://stackoverflow.com/questions/21914808/how-to-handle-asynctasks-in-actionbaractivity-fragments-when-viewpager-is-used/24386516#24386516 – LordRaydenMK Jul 11 '14 at 12:41
8 Answers
The FragmentPagerAdapter keeps additional fragments, besides the one shown, in resumed state. The solution is to implement a custom OnPageChangeListener and create a new method for when the fragment is shown.
1) Create LifecycleManager Interface The interface will have two methods and each ViewPager’s Fragment will implement it. These methods Are as follows:
public interface FragmentLifecycle {
public void onPauseFragment();
public void onResumeFragment();
}
2) Let each Fragment implement the interface Add iplements statement for each class declaration:
public class FragmentBlue extends Fragment implements FragmentLifecycle
public class FragmentGreen extends Fragment implements FragmentLifecycle
public class FragmentPink extends Fragment implements FragmentLifecycle
3) Implement interface methods in each fragment In order to check that it really works as expected, I will just log the method call and show Toast:
@Override
public void onPauseFragment() {
Log.i(TAG, "onPauseFragment()");
Toast.makeText(getActivity(), "onPauseFragment():" + TAG, Toast.LENGTH_SHORT).show();
}
@Override
public void onResumeFragment() {
Log.i(TAG, "onResumeFragment()");
Toast.makeText(getActivity(), "onResumeFragment():" + TAG, Toast.LENGTH_SHORT).show();
}
4) Call interface methods on ViewPager page change You can set OnPageChangeListener on ViewPager and get callback each time when ViewPager shows another page:
pager.setOnPageChangeListener(pageChangeListener);
5) Implement OnPageChangeListener to call your custom Lifecycle methods
Listener knows the new position and can call the interface method on new Fragment with the help of PagerAdapter. I can here call onResumeFragment() for new fragment and onPauseFragment() on the current one.
I need to store also the current fragment’s position (initially the current position is equal to 0), since I don’t know whether the user scrolled from left to right or from right to left. See what I mean in code:
private OnPageChangeListener pageChangeListener = new OnPageChangeListener() {
int currentPosition = 0;
@Override
public void onPageSelected(int newPosition) {
FragmentLifecycle fragmentToShow = (FragmentLifecycle)pageAdapter.getItem(newPosition);
fragmentToShow.onResumeFragment();
FragmentLifecycle fragmentToHide = (FragmentLifecycle)pageAdapter.getItem(currentPosition);
fragmentToHide.onPauseFragment();
currentPosition = newPosition;
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) { }
public void onPageScrollStateChanged(int arg0) { }
};
I didn't write the code. Full tutorial here: http://looksok.wordpress.com/2013/11/02/viewpager-with-detailed-fragment-lifecycle-onresumefragment-including-source-code/

- 3,790
- 4
- 37
- 48

- 542
- 5
- 5
-
1getActivity() in onResumeFragment might return Null(atleast in my case). Solution might be to pass the context(or activity) via the interface. E.g. public void onResumeFragment(Activity activity) – Pranaysharma Jan 27 '16 at 07:02
-
3In my case 'getItem();' returned fragment without views. I have solved it by using 'instantiateItem'. http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html#instantiateItem(android.view.ViewGroup, int) – Alexey Jan 28 '16 at 12:20
-
Example: http://www.alexandroid.net/android/fragments/viewpager-fragments-onpageselectedonpageunselected/ – Alexey Jan 28 '16 at 12:41
-
10not working. most adapters' `getItem(pos)` return new instance of fragment, but we need cached added to fragment manager fragment. so you'll call `.onPauseFragment()` on freshly created not attached to activity instance. don't copy-paste untested code. and why the hell it is accepted – vigilancer Apr 21 '17 at 13:07
-
1getActivity return null that is because as @vigilancer told most adapters' getItem(pos) return new instance...If you cache that is not – Ucdemir Apr 29 '18 at 16:05
-
1The fragment returned by onPageSelected(currentPosition) will not be the same fragment that WAS visible. It will be a totally new Fragment on which onCreateView has not yet been called and won't be called until you return to that position. If you want to work with the Fragment that is no longer visible, cache it but make sure to nullify it when you no longer need it. – user1608385 Aug 25 '19 at 06:36
if your Fragment extend android.support.v4.app.Fragment
you can use this, it works for me.
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (!isVisibleToUser) {
//do sth..
}
}

- 216
- 2
- 10
-
when the fragment is first created, inside this method, `getActivity()` or `getContext()` will return null. I personally prefer the `onPageSelected()` approach more. – Sira Lam Nov 06 '17 at 07:00
-
setUserVisibleHint is deprecated now. is there any alternative for it – Anil Ugale Feb 24 '20 at 11:52
user method pager.setOffscreenPageLimit(numbr) to set how many fragments you want in stack to be hold.

- 129
- 3
-
4The default value is 1. Which means the previous and next fragment are kept in idle state. – LordRaydenMK Jul 11 '14 at 12:55
-
view pager always has a minimum of 3 pages loaded at a time.and my question is how do i get a callback when one of the pages becomes visible. – shreyas Jul 11 '14 at 12:56
Override setUserVisibleHint()
. This method will call once the fragment is visible to the user.

- 21,252
- 9
- 60
- 109

- 385
- 1
- 6
Override setUserVisibleHint() this will call when fragment is visible to the user

- 419
- 5
- 10
-
-
yes..But if you have multple fragments in a viewpager that method would be useful – venu46 Jul 06 '18 at 18:11
-
You just need to test if (getUserVisibleHint) Cuz this function returns weather its visible or not. Make sure u call it after super method. – AouledIssa Jul 06 '18 at 18:13
Solve your problem:
public class FragmentVisibleHelper implements LifecycleObserver {
private static final String TAG = "VipVisibleHelper";
public interface IVisibleListener {
void onVisible();
void onInVisible();
}
boolean mIsVisibleToUser;
boolean mStarted = false;
volatile boolean mIsCalledVisible = false;
volatile boolean mIsCalledInvisible = false;
IVisibleListener mListener;
public void setListener(IVisibleListener mListener) {
this.mListener = mListener;
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
void onResume() {
Log.d(TAG, String.format("%-60s %s", this.toString(), "onResume() called:"));
if (mIsVisibleToUser) {
dispatchVisible();
}
}
private void dispatchVisible() {
Log.d(TAG, String.format("%-60s %s", this.toString(), "dispatchVisible() called mIsCalledVisible = [" + mIsCalledVisible + "] mIsCalledInvisible = [" + mIsCalledInvisible + "] "));
if (!mIsCalledVisible) {
mIsCalledVisible = true;
mIsCalledInvisible = false;
if (Profile.LOG) {
Log.d(TAG, String.format("%-60s %s", this.toString(), "dispatchVisible() called onVisible"));
}
if (mListener != null) {
mListener.onVisible();
}
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
void onPause() {
Log.d(TAG, String.format("%-60s %s", this.toString(), "onPause() called:"));
if (mIsVisibleToUser) {
dispatchInvisible();
}
}
private void dispatchInvisible() {
Log.d(TAG, String.format("%-60s %s", this.toString(), "dispatchInvisible() called mIsCalledVisible = [" + mIsCalledVisible + "] mIsCalledInvisible = [" + mIsCalledInvisible + "] "));
if (!mIsCalledInvisible) {
mIsCalledInvisible = true;
mIsCalledVisible = false;
if (Profile.LOG) {
Log.d(TAG, String.format("%-60s %s", this.toString(), "dispatchInvisible() called onInVisible"));
}
if (mListener != null) {
mListener.onInVisible();
}
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
void onStart() {
Log.d(TAG, String.format("%-60s %s", this.toString(), "onStart() called"));
mStarted = true;
if (mIsVisibleToUser) {
dispatchVisible();
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void onStop() {
Log.d(TAG, String.format("%-60s %s", this.toString(), "onStop() called"));
if (mIsVisibleToUser) {
dispatchInvisible();
}
mStarted = false;
}
public void setUserVisibleHint(boolean isVisibleToUser) {
Log.d(TAG, String.format("%-60s %s", this.toString(), "setUserVisibleHint() called with: isVisibleToUser = [" + isVisibleToUser + "]:"));
mIsVisibleToUser = isVisibleToUser;
if (mStarted) { // fragment have created
if (mIsVisibleToUser) {
dispatchVisible();
} else {
dispatchInvisible();
}
}
}
public boolean isVisibleToUser() {
return mIsVisibleToUser;
}
}

- 47,830
- 31
- 106
- 135

- 21
- 5
The fragment's lifecycle methods are not called when swiping between fragments. You can use ViewPager.SimpleOnPageChangeListener
to solve this problem. The sample code is as bellow (in Kotlin).
// other code
mViewPager.addOnPageChangeListener(object: ViewPager.SimpleOnPageChangeListener() {
override fun onPageSelected(position: Int) {
val oldPosition = mViewPager.currentItem
val oldFragment = mViewPager.adapter?.instantiateItem(mViewPager, oldPosition)
oldFragment.onPauseStuff() // Hint: do as here call onPause
val newFragment = mViewPager.adapter?.instantiateItem(mViewPager, position)
newFragment.onResumeStuff() // Hint: do as here call onResume
}
// other code

- 51
- 5
Inside pager adapter you can put this method.
public Object instantiateItem(@NonNull ViewGroup container, int position) {
Fragment fragment = fragments.get(position);
if (fragment == null) {
fragment = (Fragment) super.instantiateItem(container, position);
fragments.put(position, fragment);
}
return fragment;
}
public Fragment getFragment(int position) {
return fragments.get(position);
}
Then inside page change listener you can get current fragment and you can run your method inside your fragment.
currentFragment = adapter.getFragment(viewPager.getCurrentItem());
((DetailNewsFragment)currentFragment).runYourMethod();
Special don`t use adapter.getItem(position). because its return new instance of a fragment.

- 13
- 7