Cycle de vie des fragments - quelle méthode est appelée show / hide?

99

J'utilise la méthode suivante pour basculer entre les fragments (dans mon NavigationDrawer) en les affichant / les masquant.

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;
    }

Ce que je ne sais pas, c'est quelle méthode du cycle de vie des fragments est appelée lorsque je l'affiche ou la masque? (puisqu'il n'y a pas de méthode telle que onShow () ou onHide () je ne sais pas trop quoi utiliser). Je souhaite effectuer des actions spécifiques lors de l'affichage et du masquage d'un certain fragment.

Philipp Jahoda
la source
lorsque vous appelez Fragment.show () puis à un moment donné plus tard, le fragment se déclenche onCreate(), suivi de onCreateDialog(), suivi deonCreateView()
Someone Somewhere

Réponses:

122

Semblable au cycle de vie des activités, Android appelle onStart () lorsque le fragment devient visible. onStop()est normalement appelé lorsque fragment devient invisible, mais il peut également être appelé plus tard dans le temps.

En fonction de votre disposition, Android peut onStart()même appeler lorsque votre fragment n'est pas encore visible, mais qu'il appartient à un conteneur parent visible. Par exemple, ceci est valable pour android.support.v4.view.ViewPagerce qui vous oblige à remplacer la Fragment.setUserVisibleHint()méthode. Dans tous les cas, si vous avez besoin d'enregistrer / désenregistrer des BroadcastReceivers ou d'autres écouteurs, vous pouvez utiliser en toute sécurité des méthodes onStart()et onStop()car elles seront toujours appelées.

Remarque: certains conteneurs de fragments peuvent conserver les fragments invisibles démarrés. Pour gérer cette situation, vous pouvez passer outre Fragment.onHiddenChanged(boolean hidden). Selon la documentation , un fragment doit être à la fois démarré et visible (non masqué) , pour être visible par l'utilisateur.

Mise à jour: Si vous utilisez, android.support.v4.widget.DrawerLayoutun fragment sous le tiroir reste démarré et visible même lorsque le tiroir est ouvert. Dans ce cas , vous devez utiliser DrawerLayout.setDrawerListener()et écouter onDrawerClosed()et onDrawerOpened()callbacks.

Sergej Shafarenka
la source
14
onStopet onPausene sont pas appelés lorsqu'un fragment devient invisible à l'aide d'une transaction. Néanmoins onHiddenChangedest appelé comme le suggère s1rius réponse
Yoann Hercouet
Cela ne fonctionne pas dans NavigationDrawer. onHiddenChanged n'est pas appelé sur la bibliothèque de support v4 / v11. onStart et onResume ne seront également pas appelés à chaque fois, lorsque la disposition du tiroir s'ouvre.
drdrej
@drdrej Le problème est que le tiroir ne cache pas complètement le fragment ci-dessous. Si vous utilisez DrawerLayout à partir de la bibliothèque de support, vous devez utiliser DrawerListener.
sergej shafarenka
69

Je @Override cette méthode et résout mon problème:

@Override
public void onHiddenChanged(boolean hidden) {
    super.onHiddenChanged(hidden);
    if (hidden) {
        //do when hidden
    } else {
       //do when show
    }
}
s1rius
la source
1
J'ai essayé de ne pas résoudre mais en utilisant setUserVisibleHintcomme indiqué dans stackoverflow.com/a/18375436/1815624 fonctionne
CrandellWS
36

bien sûr, vous pouvez @Override la méthode suivante pour le faire:

@Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
            // Do your Work
        } else {
            // Do your Work
        }
    }
Biraj Zalavadia
la source
Et on peut facilement savoir si le fragment est visible par l'utilisateur ou non en appelantgetUserVisibleHint()
ARiF
2
setUserVisibleHint fonctionne avec le pager de vue mais pas avec le conteneur de fragment normal.
MikeL
Merci, ça résout mon problème :)
RAJESH KUMAR ARUMUGAM
Cela a fonctionné pour moi sur ViewPager. onHiddenChanged n'a pas fonctionné.
live-love
J'ai résolu mon problème!
Jad Chahine
3

Le comportement du pager du fragment dans la vue est différent avec le conteneur de fragment normal.

Essayez ce 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;
    }
Alan Yuan
la source
2

Essayez ce 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
}
Ahmad Aghazadeh
la source
2

Vous pouvez utiliser «onCreateView» (ou «onActivityCreated») et «onHiddenChanged». Utilisez «onCreateView» pour le premier spectacle et utilisez «onHiddenChanged» pour plus tard. 'setMenuVisibility' n'est pas appelé sur le contrôle de transaction.

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

@Override
public void onHiddenChanged(boolean hidden) {
    if (!hidden) {
        // fragment will show 
    }
    else {
        // fragment will hide
    }
}
hoi
la source
onHiddenChanged () n'est pas appelé avec mon fragment
matdev
1

Essayez simplement ceci dans votre 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;
    }
}

Et créez ce code dans onCreateView () :

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
  if(!isActive){
      init();
  }
}
roseau
la source
isVisibleToUser && getView() != nulla parfaitement fonctionné pour moi!
bobby
1

Une autre façon d'appeler la méthode fragment lorsque le fragment est visible et que vous utilisez viewpager en activité.

// tout d'abord vous créez une interface

public interface ShowFragmentVisible{
      public void showFragment();}

// Après cela, cette interface implémente l'intérieur de Fragment comme ça

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

// Maintenant va votre activité puis créez un objet d'interface et appelez à l'intérieur lorsque 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
Jatin Bansal
la source
0

setUserVisibleHintappelez avant onCreateView. et vous ne pouvez mettre à jour aucune vue à l'intérieur de setUserVisibleHint que j'utilise

public void setMenuVisibility(final boolean visible)

pour la visibilité et onHiddenChanged () n'a pas appelé pour la première fois . il appelle lorsque l'état caché change. parce que a fragment is visible by default. Afin de réaliser cette méthode pour la première fois, vous devez appeler mFragmentTransaction.hide(oldFragment)alors cela fonctionnera

Remarque

si vous souhaitez utiliser l'indicateur setUserVisible et mettre à jour la vue Utilisez cette méthode

AndroidGeek
la source
0

Bien sûr, vous pouvez remplacer setUserVisibleHintou setMenuVisibilitymais si vous avez besoin d'accéder à Contextou Activity, ils seront nuls là-dedans! Il existe une autre méthode onStartqui a toujours le contexte disponible à portée de main, mais elle ne sera appelée qu'une fois lors de la création du fragment et si vous commencez à vous déplacer entre vos fragments dans un pager, vous verrez qu'il ne sera pas appelé dans la seconde vue et après .

Alors ... que faire maintenant?

La solution de contournement est assez simple, à utiliser onStartpour la première visite et setMenuVisibilitypour les suivantes. Votre code ressemblera probablement à ci-dessous:

Classe de fragment:

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();
}

Cette méthode Contextsera toujours disponible pour la doSth()méthode.

AmiNadimi
la source
0

Seul cela a fonctionné pour moi !! et setUserVisibleHint(...)est maintenant obsolète (j'ai joint des documents à la fin), ce qui signifie que certaines autres réponses sont obsolètes ;-)

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();
    }
}

Testé et fonctionne également avec NaviagationDrawer, il y isMenuVisible()aura toujours du retour true(et cela onResume()semble suffisant, mais nous voulons soutenir ViewPageraussi).

setUserVisibleHintest obsolète. En cas de substitution de cette méthode, le comportement implémenté lors de la transmission truedoit être déplacé vers Fragment.onResume(), et le comportement implémenté lors de la transmission falsedoit être déplacé vers Fragment.onPause().

Top maître
la source