El fragmento onResume () y onPause () no se llama en backstack

Tengo múltiples fragmentos dentro de una actividad. Al hacer clic en un botón, comienzo un nuevo fragmento y lo agrego a backstack. Naturalmente, esperaba la onPause() método de Fragmento actual y onResume() de nuevo Fragmento a llamar. Bueno, no está sucediendo.

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

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

Lo que esperaba, era,

  1. Cuando se hace clic en el botón, Fragmento de inicio de sesión se reemplaza con InicioFragmento, onPause() of Fragmento de inicio de sesión y onResume() of InicioFragmento se llama
  2. Cuando se presiona atrás, InicioFragmento se sale y Fragmento de inicio de sesión se ve, y onPause() of InicioFragmento y onResume() of Fragmento de inicio de sesión se llama.

Lo que estoy consiguiendo es,

  1. Cuando se hace clic en el botón, InicioFragmento está reemplazando correctamente Fragmento de inicio de sesión, enReanudar() de InicioFragmento se llama, pero onPause() de Fragmento de inicio de sesión nunca se llama.
  2. Cuando se presiona hacia atrás, InicioFragmento aparece correctamente para revelar Fragmento de inicio de sesión, en Pausa() de InicioFragmento recibe una llamada, pero onResume() de Fragmento de inicio de sesión nunca se llama.

¿Es este el comportamiento normal? Por que es onResume() of Fragmento de inicio de sesión no me llaman cuando presiono el botón Atrás.

preguntado el 04 de julio de 12 a las 10:07

Agregue el código de actividad que maneja los fragmentos. -

tengo el problema de la muestra, en pausa no me llaman, ¿cómo resolvió esto?

Tuve el mismo problema pero me di cuenta de que estaba usando ft2.add(); en lugar de ft2.replace(). Solo otra razón sería si su actividad mantiene una referencia al fragmento (agregándolo a una colección o asignándolo a una variable de clase):

Estoy teniendo el mismo problema. Noté que .replace() llamará a los métodos de ciclo de vida necesarios, pero esencialmente destruye el fragmento. Además, onSaveInstanceState es no llamado. Como tal, no puedo mantener su estado. Entonces, necesito usar add, pero onResume/Pause no se llama :( -

FWIW, mi experiencia es que los fragmentos de la biblioteca de soporte llaman a Pausa y a Reanudar al empujar/abrir backstack, pero los fragmentos integrados de Android no lo hacen. Todavía no he encontrado una solución adecuada para eso. -

20 Respuestas

los fragmentos onResume() or onPause() se llamará sólo cuando las Actividades onResume() or onPause() se llama. Están estrechamente acoplados a la Activity.

Lea la Manejo de la sección Fragment Lifecycle de este artículo.

contestado el 22 de mayo de 14 a las 11:05

En el artículo, se dice que "una vez que la actividad alcanza el estado reanudado, puede agregar y eliminar libremente fragmentos de la actividad. Por lo tanto, solo mientras la actividad está en el estado reanudado, el ciclo de vida de un fragmento puede cambiar de forma independiente". ¿Significa esto que se puede llamar al fragmento onResume incluso si no se llama a la actividad onResume? - v4r

en cuanto a los fragmentos nativos (no compatibles) en 4.4 (no estoy seguro si es cierto para versiones anteriores) onPause() y onResume() se llaman no solo cuando estos eventos ocurren en la actividad, sino también cuando llamas a replace() o agregas ()/remove() mientras realiza la transacción, por lo que esta respuesta es engañosa al menos para las versiones recientes de Android. - Dmide

De acuerdo con ese documento, el fragmento en realidad debería moverse al estado detenido cuando se cambia a la pila trasera. Pero no solo onPause y onResume no son llamados, tampoco onStop y onStart, o cualquier otro método de ciclo de vida. Así que la guía es definitivamente engañosa. - benkc

Aunque no está relacionado, encontré esta pregunta mientras buscaba mi problema de onPause() ser llamado después onSaveInstanceState() en lugar de antes. Esto se puede reproducir si usted a un niño diferente en mi FragmentStatePagerAdapter (digamos que pasa del niño 0 al niño 2, nota personal, esto sucede porque el niño 0 se destruye cuando el niño 2 se abre) - sufí

No estoy seguro de lo que quieres decir. Llamar a ft.replace debería activar onPause (del fragmento reemplazado) y onResume (del fragmento reemplazado). Esto se hace independientemente de cualquier actividad... - Suricata rebelde

  • Desde que has usado ft2.replace(), FragmentTransaction.remove() se llama al método y el Loginfragment será eliminado. Referirse a este. Entonces onStop() of LoginFragment será llamado en lugar de onPause(). (Ya que el nuevo fragmento reemplaza completamente al antiguo).
  • Pero como también has usado ft2.addtobackstack(), el estado de la Loginfragment se guardará como un paquete y cuando haga clic en el botón Atrás desde HomeFragment, onViewStateRestored() será llamado seguido de onStart() of LoginFragment. Así que eventualmente onResume() no se llamará.

Respondido 27 Abr '13, 15:04

onViewStateRestored se llama si tienes setRetainInstance(true) - Farid

y setRetainInstance actualmente está en desuso a favor del patrón viewModel :/ - Izadi Egizábal

Aquí está mi versión más robusta de la respuesta de Gor (el uso de fragments.size() no es confiable debido a que el tamaño no se reduce después de que se abre el fragmento)

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

Y el método '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;
}

respondido 24 nov., 16:17

Si realmente desea reemplazar un fragmento dentro de otro fragmento, debe usar Fragmentos anidados.

En tu código debes reemplazar

final FragmentManager mFragmentmanager =  getFragmentManager();

con

final FragmentManager mFragmentmanager =  getChildFragmentManager();

Respondido el 11 de diciembre de 15 a las 23:12

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
            }

        }
    });

pero tenga cuidado si hay más de un fragmento visible

Respondido 13 Oct 16, 14:10

Gracias, funciona, pero si solo se ve un fragmento (entonces, ViewPager con fragmentos hará referencia a sus fragmentos). - CoolMind

Tengo un código muy parecido al tuyo y si funciona onPause() y onResume(). Al cambiar el fragmento, estas funciones se activan respectivamente.

Código en fragmento:

 @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");

}

Registro cuando cambio de fragmento:

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

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

Acción cuando vuelvo a pulsar (en la actividad donde cargo el fragmento):

@Override
public void onBackPressed() {

    int count = getFragmentManager().getBackStackEntryCount();

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

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

 }

contestado el 19 de mayo de 17 a las 21:05

Depende de cómo esté "cambiando" su fragmento. Si usted add y luego popVolver entonces onResume no será llamado. Probablemente eres replacing fragmentos y en popBack obtienes onResume devolución de llamada disparada - Farid

Yo uso en mi actividad - KOTLIN

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

                if (f?.tag == "MyFragment")
                {
                    //doSomething
                }
            }

contestado el 10 de mayo de 19 a las 23:05

Lo que hago en el fragmento de niño:

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

Y luego anule onResume en ParentFragment

Respondido el 10 de diciembre de 17 a las 09:12

Nunca debe llamar a los métodos del ciclo de vida manualmente, especialmente uno dentro del otro: linea de quiebre

@breakline esta técnica funciona. ¿Tienes alguna otra manera? - Vikash Parajulí

Sí, debe agregar su propia implementación para llamar porque el sistema también llama a los métodos del ciclo de vida y si llama a los métodos del ciclo de vida uno dentro del otro de esta manera, podría (y probablemente lo hará) causar problemas posteriores. - linea de quiebre

Aunque con un código diferente, experimenté el mismo problema que el OP, porque originalmente usé

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

en lugar de

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

Con "reemplazar", el primer fragmento se vuelve a crear cuando regresa del segundo fragmento y, por lo tanto, también se llama a onResume().

respondido 26 nov., 18:17

Esto no es una respuesta, ¿qué pasa si "agregar" es obligatorio para el diseño de alguien? - Farid

Si agrega el fragmento en XML, no puede intercambiarlos dinámicamente. Lo que sucede es que son demasiado, por lo que los eventos no se activan como cabría esperar. El problema está documentado en esta pregunta. FragmenManager reemplaza hace superposición

Convierta middle_fragment en un FrameLayout, cárguelo como se muestra a continuación y sus eventos se activarán.

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

contestado el 23 de mayo de 17 a las 13:05

Puedes probar esto

Paso 1: invalide el método Tabselected en su actividad

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

Paso 2: Usando el método estático haz lo que quieras en tu fragmento,

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

Respondido el 20 de enero de 16 a las 12:01

onPause() El método funciona en la clase de actividad que puedes usar:

public void onDestroyView(){
super.onDestroyView    
}

para el mismo fin..

Respondido 02 Abr '17, 20:04

Basado en la respuesta de @Gor Escribí similar en Kotlin. Coloque este código en onCreate() de una actividad Funciona para un fragmento visible. Si usted tiene ViewPager con fragmentos, llamará ViewPagerfragmento de , no uno anterior.

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

Despues de leer https://medium.com/@elye.project/puzzle-fragment-stack-pop-cause-issue-on-toolbar-8b947c5c07c6 Comprendí que sería mejor en muchas situaciones adjuntar nuevos fragmentos con replaceno, add. Entonces una necesidad en onResume en algunos casos desaparecerá.

Respondido 02 ago 18, 13:08

para mí, la causa fue usar navGraph para cambiar entre fragmentos

app:navGraph

cree el fragmento como este (en Kotlin) y luego se llamará a todas las funciones del ciclo de vida

val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.nav_host_fragment, fragment)
transaction.addToBackStack(null)
transaction.commit()

Respondido el 01 de junio de 21 a las 15:06

tu simple no puedes añadir un fragmento a un fragmento. Esto debe suceder en FragmentActivity. Supongo que está creando LoginFragment en FragmentActivity, por lo que para que esto funcione, debe agregar HomeFragment a través de FragmentActivity cuando se cierra el inicio de sesión.

El punto general es que necesita una clase FragmentActivity desde donde agrega cada fragmento al FragmentManager. Está imposible para hacer esto dentro de una clase Fragmento.

Respondido 11 Oct 13, 17:10

Sí, están dentro de una actividad de fragmento. - krishnabhadra

si los fragmentos se agregan dinámicamente, puede agregar tantos fragmentos como desee a un fragmento pero no a los definidos en xml etiqueta - Argumento ilegal

Los fragmentos anidados ahora son totalmente compatibles con AndroidX. - Aberaud

Un fragmento siempre debe estar incrustado en una actividad y el ciclo de vida del fragmento se ve directamente afectado por el ciclo de vida de la actividad del host. Por ejemplo, cuando la actividad está en pausa, también lo están todos los fragmentos, y cuando la actividad se destruye, también lo están todos los fragmentos.

Respondido 16 Jul 14, 12:07

Siga los pasos a continuación y obtendrá la respuesta necesaria

1- Para ambos fragmentos, cree uno nuevo padre abstracto.
2- Agregue un método abstracto personalizado que ambos deben implementar.
3- Llámalo desde la instancia actual antes de reemplazarlo con la segunda.

Respondido 09 Abr '18, 22:04

¿Cómo ayuda en una situación en la que un usuario regresa del fragmento 2 al fragmento 1? - CoolMind

llamar ft.replace debería activar onPause (del fragmento reemplazado) y onResume (del fragmento reemplazado).

Me doy cuenta de que su código se infla login_fragment en el fragmento de inicio, y tampoco devuelve las vistas en onCreateView. Si se trata de errores tipográficos, ¿puede mostrar cómo se llama a estos fragmentos desde su actividad?

respondido 20 nov., 18:09

Esto no es una respuesta, ¿qué pasa si "agregar" es obligatorio para el diseño de alguien? - Farid

Hay dos posibles métodos de anulación garantizados para ser llamados cuando aparece/desaparece un fragmento.

oncreateview/ondestroyview: se llama cada vez que cambia la visibilidad del fragmento

onpause/onresume: se llama cuando la aplicación está cerrada por un dispositivo externo o se usa el reemplazo de fragmentos

Si desea crear un enlace como lo hice yo, puede recibir una notificación cada vez que se cierre un fragmento y detectar cualquier situación sin crear una llamada duplicada, ya que a veces se pueden llamar ambos.

intente extender la clase de fragmento y agregue una bandera booleana en ambas anulaciones para que pueda capturar la apertura y el cierre con seguridad sin duplicar

Respondido 26 Oct 21, 03:10

Al crear una transacción de fragmento, asegúrese de agregar el siguiente código.

// Replace whatever is in the fragment_container view with this fragment, 
// and add the transaction to the back stack 
transaction.replace(R.id.fragment_container, newFragment); 
transaction.addToBackStack(null); 

También asegúrese de confirmar la transacción después de agregarla a backstack

respondido 07 mar '13, 13:03

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.