Fragment lifecycle - which method is called upon show / hide?

AndroidAndroid FragmentsLifecycleFragmenttransaction

Android Problem Overview


I am using the following method to switch between Fragments (in my NavigationDrawer) by showing / hiding them.

protected void showFragment(int container, Fragment fragment, String tag, String lastTag, boolean addToBackStack ) {

        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();

        if ( lastTag != null && !lastTag.equals("")) {
            Fragment lastFragment = fragmentManager.findFragmentByTag( lastTag );
            if ( lastFragment != null ) {
                transaction.hide( lastFragment );
            }
        }

        if ( fragment.isAdded() ) {
            transaction.show( fragment );
        }
        else {
            transaction.add( container, fragment, tag );
        }

        if ( addToBackStack ) {
            transaction.addToBackStack( tag );
        }

        transaction.commit();
        
        // set the active tag
        activeFragTag = tag;
	}

What I am unclear about is which method of the Fragments lifecycle is called when I show or hide it? (since there is no method such as onShow() or onHide() im not quite sure what to use). I want to perform specific actions upon showing and hiding a certain Fragment.

Android Solutions


Solution 1 - Android

Similar to activity lifecycle, Android calls onStart() when fragment becomes visible. onStop() is normally called when fragment becomes invisible, but it can also be called later in time.

Depending on your layout Android can call onStart() even, when your Fragment is not yet visible, but it belongs to a visible parent container. For instance, this is valid for android.support.v4.view.ViewPager which requires you to override Fragment.setUserVisibleHint() method. In any case, if you need to register/unregister BroadcastReceivers or other listeners, you can safely use onStart() and onStop() methods because those will be called always.

Note: Some fragment containers can keep invisible fragments started. To handle this situation you can override Fragment.onHiddenChanged(boolean hidden). According to the documentation, a fragment must be both started and visible (not hidden), to be visible to the user.

Update: If you use android.support.v4.widget.DrawerLayout then a fragment below the drawer stays started and visible even when drawer is open. In this case you need to use DrawerLayout.setDrawerListener() and listen for onDrawerClosed() and onDrawerOpened() callbacks.

Solution 2 - Android

I @Override this method and resolve my problem:

@Override
public void onHiddenChanged(boolean hidden) {
	super.onHiddenChanged(hidden);
	if (hidden) {
		//do when hidden
	} else {
       //do when show
	}
}

Solution 3 - Android

of course you can @Override the following method to do so:

@Override
	public void setUserVisibleHint(boolean isVisibleToUser) {
		super.setUserVisibleHint(isVisibleToUser);
		if (isVisibleToUser) {
			// Do your Work
		} else {
			// Do your Work
		}
	}

Solution 4 - Android

You can use 'onCreateView'(or 'onActivityCreated') and 'onHiddenChanged'. Use 'onCreateView' for first show and use 'onHiddenChanged' for later. 'setMenuVisibility' is not called on transaction control.

@Override
public View OnCreateView() {
   // fragment will show first
}

@Override
public void onHiddenChanged(boolean hidden) {
	if (!hidden) {
		// fragment will show 
	}
	else {
        // fragment will hide
	}
}

Solution 5 - Android

Fragment in view pager behaviour is different with regular fragment container.

Try this code:

    boolean mIsVisibleToUser;

    /**
     * is visible to user
     */
    public void show() {
        //do when show
    }

    /**
     * is invisible to user
     */
    public void hide() {
        //do when gone
    }

    @Override
    public void onResume() {
        super.onResume();
        if (!mIsVisibleToUser && getUserVisibleHint()) {
            mIsVisibleToUser = true;
            show();
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        if (mIsVisibleToUser && getUserVisibleHint()) {
            mIsVisibleToUser = false;
            hide();
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isResumed()) {
            if (mIsVisibleToUser != isVisibleToUser) {
                mIsVisibleToUser = isVisibleToUser;
                if (isVisibleToUser) show();
                else hide();
            }
        }
    }

    public boolean isVisibleToUser() {
        return mIsVisibleToUser;
    }

Solution 6 - Android

Try this code:

@Override
public void setUserVisibleHint(boolean visible)
{
    super.setUserVisibleHint(visible);
    if (visible && isResumed())
    {
         onResume();
    }
}

@Override
public void onResume()
{
    super.onResume();
    if (!getUserVisibleHint())
    {
        return;
    }

    //Add your code this section
}

Solution 7 - Android

Just try this in your setUserVisibleHint()

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if(isVisibleToUser && getView() != null){
        isActive = true;
        init();
    }else if(isVisibleToUser && getView() == null){
        isActive = false;
    }else{
        isActive = true;
    }
}

And create this code in onCreateView() :

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
  if(!isActive){
      init();
  }
}

Solution 8 - Android

> Another way to calling fragment method when fragment is visible and you use viewpager in activity.

//first of all you create a interface

public interface ShowFragmentVisible{
      public void showFragment();}

//After that this interface implement inside Fragment like that

      public class MyFragment extends Fragment implements 
         ShowFragmentVisible {
            @Override
public void showFragment() {
}

// Now goes your Activity then create object of interface and call inside when addOnViewpagerListener

   ShowFragmentVisible showFragmentVisible;

@Override
public void onAttachFragment(Fragment fragment) {
    super.onAttachFragment(fragment);

    if (fragment instanceof ShowFragmentVisible) {
        showFragmentVisible = (ShowFragmentVisible) fragment;
    }
   
}
     //your viewpager method
    viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {
            if (position==0){
                showFragmentVisible.showFragment();

           }
          
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });
     

this is another alternative,but its work for me successfully

Solution 9 - Android

Only this worked for me!! and setUserVisibleHint(...) is now deprecated (I attached docs at end), which means some other answers are deprecated ;-)

public class FragmentFirewall extends Fragment {
    /**
     * Required cause "setMenuVisibility(...)" is not guaranteed to be,
     * called after "onResume()" and/or "onCreateView(...)" method.
     */
    protected void didVisibilityChange() {
        Activity activity = getActivity();
        if (isResumed() && isMenuVisible()) {
            // Once resumed and menu is visible,
            // at last our Fragment is really visible to user.
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        didVisibilityChange();
    }

    @Override
    public void setMenuVisibility(boolean visible) {
        super.setMenuVisibility(visible);
        didVisibilityChange();
    }
}

Tested and works with NaviagationDrawer as well, there isMenuVisible() will always return true (and onResume() seems enough, but we want to support ViewPager too).

>setUserVisibleHint is deprecated. If overriding this method, behavior implemented when passing in true should be moved to Fragment.onResume(), and behavior implemented when passing in false should be moved to Fragment.onPause().

Solution 10 - Android

setUserVisibleHint call before onCreateView. and you can't update any View inside setUserVisibleHint I use

public void setMenuVisibility(final boolean visible)

for visibility and onHiddenChanged() didn't call for the first time. it calls when the hidden state changes. because a fragment is visible by default. In order to achieve this method for the first time you have to call mFragmentTransaction.hide(oldFragment) then it will work

Note

if you want to use setUserVisible hint and update View Use this method

Solution 11 - Android

Of course you could override setUserVisibleHint or setMenuVisibility but if you need to access Context or Activity, they will be null in there! There is another method onStart which always has the context available at hand, but it will only get called once upon creation of fragment and if you start moving between your fragments in a pager you will see that it won't get called in second view and afterwards.

So... what to do now?

The workaround is quite easy, use onStart for the first visit and setMenuVisibility for later ones. Your code will probably look like below :

Fragment class:

public class MyFragmentClass{
    private boolean isCurrentVisible = false;
...

@Override
public void onStart() {
    super.onStart();
    if (isCurrentVisible)
        doSth();
}

@Override
public void setMenuVisibility(boolean menuVisible){
    super.setMenuVisibility(menuVisible);
    this.isCurrentVisible = menuVisible;
    if(menuVisible && getContext() != null)
        doSth();
}

This way Context will always be available to doSth() method.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPhilipp JahodaView Question on Stackoverflow
Solution 1 - Androidsergej shafarenkaView Answer on Stackoverflow
Solution 2 - Androids1riusView Answer on Stackoverflow
Solution 3 - AndroidBiraj ZalavadiaView Answer on Stackoverflow
Solution 4 - AndroidhoiView Answer on Stackoverflow
Solution 5 - AndroidAlan YuanView Answer on Stackoverflow
Solution 6 - AndroidAhmad AghazadehView Answer on Stackoverflow
Solution 7 - AndroidreedView Answer on Stackoverflow
Solution 8 - AndroidJatin BansalView Answer on Stackoverflow
Solution 9 - AndroidTop-MasterView Answer on Stackoverflow
Solution 10 - AndroidZar E AhmerView Answer on Stackoverflow
Solution 11 - AndroidAmiNadimiView Answer on Stackoverflow