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.
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();
}
}
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
onPause()
de LoginFragment et onResume()
de HomeFragment est appelé.onPause()
de HomeFragment et onResume()
de LoginFragment Est appelé.Ce que je reçois, c'est
Est-ce le comportement normal? Pourquoi onResume()
de LoginFragment n'est-il pas appelé lorsque j'appuie sur le bouton Précédent?.
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 .
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).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é.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();
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;
}
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
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();
}
}
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();
}
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.
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();
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
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.
La méthode onPause()
fonctionne dans la classe d'activité que vous pouvez utiliser:
public void onDestroyView(){
super.onDestroyView
}
dans le même but ..
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é.
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é?
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.
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.
J'utilise dans mon activité -KOTLIN
supportFragmentManager.addOnBackStackChangedListener {
val f = supportFragmentManager.findFragmentById(R.id.fragment_container)
if (f?.tag == "MyFragment")
{
//doSomething
}
}