web-dev-qa-db-fra.com

Le fragment onResume () & onPause () n'est pas appelé sur backstack

J'ai plusieurs fragments dans une activité. Sur un bouton, je commence un nouveau fragment et l’ajoute à l’arrière-pile. Je pensais naturellement que la méthode onPause() du fragment actuel et la onResume() du nouveau fragment seraient appelées. Eh bien ça ne se passe pas.

LoginFragment.Java

public class LoginFragment extends Fragment{
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      final View view  =   inflater.inflate(R.layout.login_fragment, container, false);
      final FragmentManager mFragmentmanager =  getFragmentManager();

      Button btnHome  = (Button)view.findViewById(R.id.home_btn);
      btnHome.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view){
           HomeFragment fragment    = new HomeFragment();
           FragmentTransaction ft2   =  mFragmentmanager.beginTransaction();
           ft2.setCustomAnimations(R.anim.slide_right, R.anim.slide_out_left
                    , R.anim.slide_left, R.anim.slide_out_right);
           ft2.replace(R.id.middle_fragment, fragment);
           ft2.addToBackStack(""); 
           ft2.commit();    
         }
      });
  }

  @Override
  public void onResume() {
     Log.e("DEBUG", "onResume of LoginFragment");
     super.onResume();
  }

  @Override
  public void onPause() {
    Log.e("DEBUG", "OnPause of loginFragment");
    super.onPause();
  }
}

AccueilFragment.Java

public class HomeFragment extends Fragment{
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
     final View view  =   inflater.inflate(R.layout.login_fragment, container, false);
  }

  @Override
  public void onResume() {
     Log.e("DEBUG", "onResume of HomeFragment");
     super.onResume();
  }

  @Override
  public void onPause() {
     Log.e("DEBUG", "OnPause of HomeFragment");
     super.onPause();
  }
}

Ce à quoi je m'attendais était

  1. Lorsque vous cliquez sur le bouton, LoginFragment est remplacé par HomeFragment, onPause() de LoginFragment et onResume() de HomeFragment est appelé.
  2. Lorsque vous appuyez sur la touche Retour, HomeFragment est affiché et LoginFragment est affiché. onPause() de HomeFragment et onResume() de LoginFragment Est appelé.

Ce que je reçois, c'est

  1. Lorsque vous cliquez sur le bouton, HomeFragment remplace correctement LoginFragment, onResume () de HomeFragment est appelé, mais onPause () De LoginFragment n'est jamais appelé. .
  2. Lorsque vous appuyez de nouveau sur, HomeFragment s'affiche correctement pour révéler LoginFragment, onPause () de HomeFragment n'est pas appelé, mais onResume () De LoginFragment n'est jamais appelé. appelé.

Est-ce le comportement normal? Pourquoi onResume() de LoginFragment n'est-il pas appelé lorsque j'appuie sur le bouton Précédent?.

167
Krishnabhadra

Les fragments onResume() ou onPause() ne seront appelés que lorsque les activités onResume() ou onPause() sont appelées . Ils sont étroitement associés au Activity.

Lisez la section Gestion du cycle de vie des fragments de cet article .

157
Sagar Waghmare
  • Puisque vous avez utilisé ft2.replace(), la méthode FragmentTransaction.remove().__ est appelée et la variable Loginfragment sera supprimée. Reportez-vous à this . Donc, onStop() de LoginFragment sera appelé à la place de onPause(). (Comme le nouveau fragment Remplace complètement l'ancien).
  • Mais puisque vous avez également utilisé ft2.addtobackstack(), l'état de la Loginfragment sera sauvegardé comme un paquet et lorsque vous cliquerez sur le bouton Précédent de HomeFragment, onViewStateRestored() sera appelé suivi de onStart() de LoginFragment. Donc, finalement, onResume() ne sera pas appelé.
18
Gopal

Si vous voulez vraiment remplacer fragment à l'intérieur d'un autre fragment, utilisez Fragments imbriqués .

Dans votre code, vous devez remplacer

final FragmentManager mFragmentmanager =  getFragmentManager();

avec

final FragmentManager mFragmentmanager =  getChildFragmentManager();
8
Bersh

Voici ma version plus robuste de la réponse de Gor (l'utilisation de fragments.size () n'est pas fiable car la taille n'est pas décrémentée après la fragmentation)

getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            if (getFragmentManager() != null) {

                Fragment topFrag = NavigationHelper.getCurrentTopFragment(getFragmentManager());

                if (topFrag != null) {
                    if (topFrag instanceof YourFragment) {
                        //This fragment is being shown. 
                    } else {
                        //Navigating away from this fragment. 
                    }
                }
            }
        }
    });

Et la méthode 'getCurrentTopFragment':

public static Fragment getCurrentTopFragment(FragmentManager fm) {
    int stackCount = fm.getBackStackEntryCount();

    if (stackCount > 0) {
        FragmentManager.BackStackEntry backEntry = fm.getBackStackEntryAt(stackCount-1);
        return  fm.findFragmentByTag(backEntry.getName());
    } else {
        List<Fragment> fragments = fm.getFragments();
        if (fragments != null && fragments.size()>0) {
            for (Fragment f: fragments) {
                if (f != null && !f.isHidden()) {
                    return f;
                }
            }
        }
    }
    return null;
}
6
aaronmarino
getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            List<Fragment> fragments = getFragmentManager().getFragments();
            if (fragments.size() > 0 && fragments.get(fragments.size() - 1) instanceof YoureFragment){
                //todo if fragment visible
            } else {
                //todo if fragment invisible
            }

        }
    });

mais soyez prudent si plus d'un fragment visible

2
Gor

J'ai un code très similaire au vôtre et si ça marche onPause () et onResume (). Lors du changement de fragment, ces fonctions sont activées respectivement.

Code en fragment:

 @Override
public void onResume() {
    super.onResume();
    sensorManager.registerListener(this, proximidad, SensorManager.SENSOR_DELAY_NORMAL);
    sensorManager.registerListener(this, brillo, SensorManager.SENSOR_DELAY_NORMAL);
    Log.e("Frontales","resume");
}

@Override
public void onPause() {
    super.onPause();
    sensorManager.unregisterListener(this);
    Log.e("Frontales","Pause");

}

Se connecter lors du changement de fragment:

05-19 22:28:54.284 2371-2371/madi.cajaherramientas E/Frontales: resume
05-19 22:28:57.002 2371-2371/madi.cajaherramientas E/Frontales: Pause
05-19 22:28:58.697 2371-2371/madi.cajaherramientas E/Frontales: resume
05-19 22:29:00.840 2371-2371/madi.cajaherramientas E/Frontales: Pause
05-19 22:29:02.248 2371-2371/madi.cajaherramientas E/Frontales: resume
05-19 22:29:03.718 2371-2371/madi.cajaherramientas E/Frontales: Pause

Fragment onCreateView:

View rootView;
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    rootView = inflater.inflate(R.layout.activity_proximidad, container, false);
    ButterKnife.bind(this,rootView);
    inflar();
    setTextos();
    return rootView;
}

Action lorsque je retourne (dans l'activité où je charge le fragment):

@Override
public void onBackPressed() {

    int count = getFragmentManager().getBackStackEntryCount();

    if (count == 0) {
        super.onBackPressed();

    } else {
        getFragmentManager().popBackStack();
    }

 }
2
PepitoGrillo

Tu peux essayer ça,

Étape 1: Remplacez la méthode Tabselected dans votre activité

@Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    // When the given tab is selected, switch to the corresponding page in
    // the ViewPager.
    try {
    if(MyEventsFragment!=null && tab.getPosition()==3)
    {
        MyEvents.fragmentChanged();
    }
    }
    catch (Exception e)
    {

    }
    mViewPager.setCurrentItem(tab.getPosition());
}

Étape 2: À l'aide de la méthode statique, faites ce que vous voulez dans votre fragment.

public static void fragmentChanged()
{
    Toast.makeText(actvity, "Fragment Changed", Toast.LENGTH_SHORT).show();
}
1
Manoj Kumar

Vous simple ne pouvez pas ajouter un fragment à un fragment. Cela doit se produire dans FragmentActivity. Je suppose que vous créez le LoginFragment dans FragmentActivity. Par conséquent, pour que cela fonctionne, vous devez ajouter HomeFragment via FragmentActivity lorsque le login se ferme.

En règle générale, vous avez besoin d'une classe FragmentActivity à partir de laquelle vous ajoutez chaque fragment au FragmentManager. Il est impossible de faire cela dans une classe de fragments.

1
Nickolaus

Si vous ajoutez le fragment en XML, vous ne pouvez pas les échanger de manière dynamique. Ce qui se produit, c’est qu’ils sont excessifs, ils ne se déclenchent donc pas comme on pourrait s’y attendre. Le problème est documenté dans cette question. FragmenManager remplace fait la superposition

Transformez middle_fragment en FrameLayout et chargez-le comme ci-dessous pour que vos événements se déclenchent.

getFragmentManager().beginTransation().
    add(R.id.middle_fragment, new MiddleFragment()).commit();
1
Dustin

Ce que je fais dans un fragment d'enfant:

@Override
public void onDetach() {
   super.onDetach();
   ParentFragment pf = (ParentFragment) this.getParentFragment();
   pf.onResume();
}

Et puis remplacer onResume sur ParentFragment

1
Guillermo De Juan

Un fragment doit toujours être intégré à une activité et son cycle de vie est directement affecté par le cycle de vie de l'activité hôte. Par exemple, lorsque l'activité est suspendue, tous les fragments s'y trouvant le sont, et lorsque l'activité est détruite, tous les fragments le sont également.

0
Xar E Ahmer

La méthode onPause() fonctionne dans la classe d'activité que vous pouvez utiliser:

public void onDestroyView(){
super.onDestroyView    
}

dans le même but ..

0
Vikrant Kaloniya

Bien qu'avec un code différent, j'ai rencontré le même problème que l'OP, car j'avais initialement utilisé 

fm.beginTransaction()
            .add(R.id.fragment_container_main, fragment)
            .addToBackStack(null)
            .commit();

au lieu de

fm.beginTransaction()
                .replace(R.id.fragment_container_main, fragment)
                .addToBackStack(null)
                .commit();

Avec "replace", le premier fragment est recréé lorsque vous revenez du second fragment et donc onResume () est également appelé. 

0
Greg Holst

L'appel de ft.replace devrait déclencher onPause (du fragment remplacé) et onResume (du fragment de remplacement).

Je remarque que votre code gonfle login_fragment sur le fragment de base et ne renvoie pas non plus les vues dans onCreateView. S'il s'agit de fautes de frappe, pouvez-vous montrer comment ces fragments sont appelés depuis votre activité?

0
David Refaeli

Basé sur la réponse de @Gor j’ai écrit la même chose dans Kotlin. Placez ce code dans onCreate() d'une activité. Cela fonctionne pour un fragment visible. Si vous avez ViewPager avec des fragments, il appellera le fragment ViewPager, pas le précédent.

supportFragmentManager.addOnBackStackChangedListener {
    supportFragmentManager.fragments.lastOrNull()?.onResume()
}

Après avoir lu https://medium.com/@elye.project/puzzle-fragment-stack-pop-cause-issue-on-toolbar-8b947c5c07c6 j'ai compris qu'il serait préférable dans de nombreuses situations d'attacher de nouveaux fragments avec replace, pas add. Ainsi, un besoin dans onResume dans certains cas disparaîtra.

0
CoolMind

Suivez les étapes ci-dessous et vous obtiendrez la réponse nécessaire

1- Pour les deux fragments, créez un nouveau parent abstrait.
2- Ajouter une méthode abstraite personnalisée qui devrait être implémentée par les deux.
3- Appelez-le depuis l'instance actuelle avant de le remplacer par le second.

0
Mostafa Magdy

J'utilise dans mon activité -KOTLIN

supportFragmentManager.addOnBackStackChangedListener {
                val f = supportFragmentManager.findFragmentById(R.id.fragment_container)

                if (f?.tag == "MyFragment")
                {
                    //doSomething
                }
            }
0
Álvaro Agüero