Ciclo di vita del frammento: quale metodo viene chiamato mostra / nascondi?


99

Sto usando il seguente metodo per passare da un frammento all'altro (nel mio NavigationDrawer) mostrandoli / nascondendoli.

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

Quello che non mi è chiaro è quale metodo del ciclo di vita dei frammenti viene chiamato quando lo mostro o lo nascondo? (poiché non esiste un metodo come onShow () o onHide () non sono sicuro di cosa usare). Voglio eseguire azioni specifiche mostrando e nascondendo un determinato frammento.


quando chiami Fragment.show () poi, in un momento successivo, il frammento si attiva onCreate(), seguito da onCreateDialog(), seguito daonCreateView()
Someone Somewhere,

Risposte:


122

Simile al ciclo di vita dell'attività, Android chiama onStart () quando il frammento diventa visibile. onStop()viene normalmente chiamato quando il frammento diventa invisibile, ma può anche essere chiamato più tardi nel tempo.

A seconda del layout, Android può chiamare onStart()anche, quando il frammento non è ancora visibile, ma appartiene a un contenitore padre visibile. Ad esempio, questo è valido per il android.support.v4.view.ViewPagerquale richiede di sovrascrivere il Fragment.setUserVisibleHint()metodo. In ogni caso, se devi registrare / annullare la registrazione di BroadcastReceivers o altri ascoltatori, puoi tranquillamente utilizzare i metodi onStart()e onStop()perché quelli verranno chiamati sempre.

Nota: alcuni contenitori di frammenti possono mantenere i frammenti invisibili avviati. Per gestire questa situazione puoi eseguire l'override Fragment.onHiddenChanged(boolean hidden). Secondo la documentazione , un frammento deve essere sia avviato che visibile (non nascosto) , per essere visibile all'utente.

Aggiornamento: se si utilizza, android.support.v4.widget.DrawerLayoutun frammento sotto il cassetto rimane avviato e visibile anche quando il cassetto è aperto. In questo caso è necessario utilizzare DrawerLayout.setDrawerListener()e ascoltareonDrawerClosed() e onDrawerOpened()richiamare.


14
onStope onPausenon vengono chiamati quando un frammento diventa invisibile utilizzando una transazione. Tuttavia onHiddenChangedè chiamato come suggerisce la risposta di s1rius
Yoann Hercouet

Questo non funziona in NavigationDrawer. onHiddenChanged non viene chiamato nella libreria di supporto v4 / v11. Anche onStart e onResume verranno chiamati non ogni volta, quando si apre il layout del cassetto.
drdrej

@drdrej Il problema è che il cassetto non nasconde completamente il frammento sottostante. Se usi DrawerLayout dalla libreria di supporto, devi usare DrawerListener.
sergej shafarenka

69

@Override questo metodo e risolvo il mio problema:

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

1
Non ho provato a risolverlo, ma utilizzando setUserVisibleHintcome mostrato in stackoverflow.com/a/18375436/1815624 funziona
CrandellWS

36

ovviamente puoi @Override il seguente metodo per farlo:

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

E si può facilmente sapere se il frammento è visibile all'utente o meno chiamandogetUserVisibleHint()
ARiF

2
setUserVisibleHint funziona con il cercapersone della vista ma non con il normale contenitore di frammenti.
MikeL

Grazie, questo risolve il mio problema :)
RAJESH KUMAR ARUMUGAM

Questo ha funzionato per me su ViewPager. onHiddenChanged non ha funzionato.
live-love

Risolto il mio problema!
Jad Chahine

3

Il comportamento del pager del frammento nella visualizzazione è diverso con il normale contenitore di frammenti.

Prova questo codice:

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

2

Prova questo codice:

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

2

Puoi utilizzare "onCreateView" (o "onActivityCreated") e "onHiddenChanged". Usa "onCreateView" per il primo spettacolo e usa "onHiddenChanged" per dopo. 'setMenuVisibility' non viene chiamato sul controllo delle transazioni.

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

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

onHiddenChanged () non viene chiamato con il mio frammento
matdev

1

Prova questo nel tuo 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;
    }
}

E crea questo codice in onCreateView () :

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

isVisibleToUser && getView() != nullha funzionato perfettamente per me!
bobby

1

Un altro modo per chiamare il metodo fragment quando fragment è visibile e usi viewpager in attività.

// prima di tutto crei un'interfaccia

public interface ShowFragmentVisible{
      public void showFragment();}

// Dopodiché questa interfaccia implementa in Fragment in questo modo

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

// Ora va la tua attività, quindi crea l'oggetto dell'interfaccia e chiama all'interno quando 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

0

setUserVisibleHintchiama prima onCreateView. e non puoi aggiornare nessuna vista all'interno di setUserVisibleHint che uso

public void setMenuVisibility(final boolean visible)

per la visibilità e onHiddenChanged () non ha chiamato per la prima volta . chiama quando lo stato nascosto cambia. perché a fragment is visible by default. Per ottenere questo metodo per la prima volta devi chiamare, mFragmentTransaction.hide(oldFragment)quindi funzionerà

Nota

se vuoi usare il suggerimento setUserVisible e aggiornare la visualizzazione Usa questo metodo


0

Ovviamente potresti sovrascrivere setUserVisibleHinto setMenuVisibilityma se devi accedere a Contexto Activity, saranno nulli lì! C'è un altro metodo onStartche ha sempre il contesto a portata di mano, ma verrà richiamato solo una volta dopo la creazione del frammento e se inizi a muoverti tra i tuoi frammenti in un cercapersone vedrai che non verrà richiamato in una seconda vista e successivamente .

Quindi cosa si fa adesso?

La soluzione alternativa è abbastanza semplice, da utilizzare onStartper la prima visita e setMenuVisibilityper quelle successive. Il tuo codice apparirà probabilmente come di seguito:

Classe frammento:

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

Per di qua Context sarà sempre disponibile il doSth()metodo.


0

Solo questo ha funzionato per me !! ed setUserVisibleHint(...)è ora deprecato (ho allegato i documenti alla fine), il che significa che alcune altre risposte sono deprecate ;-)

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

Testato e funziona anche con NaviagationDrawer, isMenuVisible()tornerà sempre true(e onResume()sembra abbastanza, ma vogliamo supportare ViewPageranche noi).

setUserVisibleHintè deprecato. Se si sovrascrive questo metodo, il comportamento implementato durante il passaggio truedovrebbe essere spostato in Fragment.onResume()e il comportamento implementato durante il passaggio falsedovrebbe essere spostato in Fragment.onPause().

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.