studio how fragments backstack activity android android-fragments onbackpressed

android - how - ¿Cómo implementar onBackPressed() en fragmentos?



onbackpressed activity (30)

¿Qué hay de usar onDestroyView ()?

@Override public void onDestroyView() { super.onDestroyView(); }

¿Hay alguna manera en la que podamos implementar onBackPressed() en Android Fragment de manera similar a la forma en que implementamos en Android Activity?

Como el ciclo de vida del fragmento no tiene onBackPressed() . ¿Hay algún otro método alternativo para pasar por encima de onBackPressed() en los fragmentos de Android 3.0?


Creo que la mejor solución es

SOLUCIÓN DE JAVA

Crear una interfaz simple:

public interface IOnBackPressed { /** * If you return true the back press will not be taken into account, otherwise the activity will act naturally * @return true if your processing has priority if not false */ boolean onBackPressed(); }

Y en tu actividad

public class MyActivity extends Activity { @Override public void onBackPressed() { Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_container); if (!(fragment instanceof IOnBackPressed) || !((IOnBackPressed) fragment).onBackPressed()) { super.onBackPressed(); } } ... }

Finalmente en tu Fragmento:

public class MyFragment extends Fragment implements IOnBackPressed{ @Override public boolean onBackPressed() { if (myCondition) { //action not popBackStack return true; } else { return false; } } }

SOLUCIÓN KOTLIN

1 - Crear interfaz

interface IOnBackPressed { fun onBackPressed(): Boolean }

2 - Prepare su actividad

class MyActivity : AppCompatActivity() { override fun onBackPressed() { val fragment = this.supportFragmentManager.findFragmentById(R.id.main_container) if ((fragment as? IOnBackPressed)?.onBackPressed()!!.not()) { super.onBackPressed() } } }

3 - Implementar en tu Fragmento objetivo.

class MyFragment : Fragment(), IOnBackPressed { override fun onBackPressed(): Boolean { return if (myCondition) { //action not popBackStack true } else { false } } }


Dado que esta pregunta y algunas de las respuestas tienen más de cinco años, permítanme compartir mi solución. Este es un seguimiento y modernización de la respuesta de @oyenigun.

ACTUALIZACIÓN: En la parte inferior de este artículo, agregué una implementación alternativa utilizando una extensión de Fragmento abstracto que no involucrará a la Actividad en absoluto, lo que sería útil para cualquier persona con una jerarquía de fragmentos más compleja que involucre fragmentos anidados que requieran un comportamiento de espalda diferente.

Necesitaba implementar esto porque algunos de los fragmentos que uso tienen vistas más pequeñas que me gustaría descartar con el botón Atrás, como pequeñas vistas de información que aparecen, etc., pero esto es bueno para cualquier persona que necesite anular el comportamiento de El botón de atrás dentro de fragmentos.

Primero, define una interfaz

public interface Backable { boolean onBackPressed(); }

Esta interfaz, que yo llamo Backable (soy un stickler para las convenciones de nombres), tiene un solo método onBackPressed() que debe devolver un valor boolean . Necesitamos imponer un valor booleano porque necesitaremos saber si la pulsación del botón Atrás ha "absorbido" el evento Atrás. Devolviendo true significa que sí, y no se necesita ninguna otra acción, de lo contrario, false dice que la acción de retroceso predeterminada todavía debe tener lugar. Esta interfaz debe ser su propio archivo (preferiblemente en un paquete separado llamado interfaces ). Recuerde, separar sus clases en paquetes es una buena práctica.

Segundo, encuentra el fragmento superior.

Creé un método que devuelve el último objeto Fragment en la pila trasera. Yo uso etiquetas ... si usa ID, haga los cambios necesarios. Tengo este método estático en una clase de utilidad que se ocupa de los estados de navegación, etc ... pero, por supuesto, colóquelo donde mejor le convenga. Para la edificación, he puesto el mío en una clase llamada NavUtils .

public static Fragment getCurrentFragment(Activity activity) { FragmentManager fragmentManager = activity.getFragmentManager(); if (fragmentManager.getBackStackEntryCount() > 0) { String lastFragmentName = fragmentManager.getBackStackEntryAt( fragmentManager.getBackStackEntryCount() - 1).getName(); return fragmentManager.findFragmentByTag(lastFragmentName); } return null; }

Asegúrese de que el recuento de la pila trasera sea mayor que 0, de lo contrario, se podría ArrayOutOfBoundsException una ArrayOutOfBoundsException en tiempo de ejecución. Si no es mayor que 0, devuelve nulo. Verificaremos un valor nulo más tarde ...

Tercero, implementar en un fragmento

Implemente la interfaz de Backable en el fragmento en el que necesite anular el comportamiento del botón de retroceso. Agregue el método de implementación.

public class SomeFragment extends Fragment implements FragmentManager.OnBackStackChangedListener, Backable { ... @Override public boolean onBackPressed() { // Logic here... if (backButtonShouldNotGoBack) { whateverMethodYouNeed(); return true; } return false; } }

En la onBackPressed() , ponga la lógica que necesite. Si desea que el botón Atrás no haga estallar la pila trasera (el comportamiento predeterminado), devuelva verdadero , que su evento de respaldo ha sido absorbido. De lo contrario, devuelve falso.

Por último, en tu actividad ...

Reemplace el método onBackPressed() y agregue esta lógica:

@Override public void onBackPressed() { // Get the current fragment using the method from the second step above... Fragment currentFragment = NavUtils.getCurrentFragment(this); // Determine whether or not this fragment implements Backable // Do a null check just to be safe if (currentFragment != null && currentFragment instanceof Backable) { if (((Backable) currentFragment).onBackPressed()) { // If the onBackPressed override in your fragment // did absorb the back event (returned true), return return; } else { // Otherwise, call the super method for the default behavior super.onBackPressed(); } } // Any other logic needed... // call super method to be sure the back button does its thing... super.onBackPressed(); }

Obtenemos el fragmento actual en la pila trasera, luego realizamos una comprobación nula y determinamos si implementa nuestra interfaz Backable . Si lo hace, determine si el evento fue absorbido. Si es así, hemos terminado con onBackPressed() y podemos regresar. De lo contrario, trátelo como un respaldo normal, presione y llame al súper método.

Segunda opción para no involucrar la actividad.

A veces, no desea que la Actividad maneje esto en absoluto, y necesita manejarlo directamente dentro del fragmento. Pero, ¿quién dice que no puedes tener fragmentos con una API de prensa inversa? Solo extiende tu fragmento a una nueva clase.

Cree una clase abstracta que amplíe Fragmento e implemente la interfaz View.OnKeyListner ...

import android.app.Fragment; import android.os.Bundle; import android.view.KeyEvent; import android.view.View; public abstract class BackableFragment extends Fragment implements View.OnKeyListener { @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); view.setFocusableInTouchMode(true); view.requestFocus(); view.setOnKeyListener(this); } @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_UP) { if (keyCode == KeyEvent.KEYCODE_BACK) { onBackButtonPressed(); return true; } } return false; } public abstract void onBackButtonPressed(); }

Como puede ver, cualquier fragmento que extienda BackableFragment capturará automáticamente los clics hacia atrás utilizando la interfaz View.OnKeyListener . Simplemente llame al onBackButtonPressed() abstracto onBackButtonPressed() desde el método implementado onKey() usando la lógica estándar para discernir la presión del botón Atrás. Si necesita registrar clics de tecla distintos al botón de retroceso, solo asegúrese de llamar al super método al anular onKey() en su fragmento, de lo contrario, anulará el comportamiento en la abstracción.

Fácil de usar, solo extender e implementar:

public class FragmentChannels extends BackableFragment { ... @Override public void onBackButtonPressed() { if (doTheThingRequiringBackButtonOverride) { // do the thing } else { getActivity().onBackPressed(); } } ... }

Dado que el método onBackButtonPressed() en la súper clase es abstracto, una vez que lo extienda, debe implementar onBackButtonPressed() . Devuelve void porque solo necesita realizar una acción dentro de la clase de fragmento y no necesita transmitir la absorción de la prensa a la Actividad. Asegúrese de llamar al onBackPressed() Activity onBackPressed() si lo que está haciendo con el botón de retroceso no requiere manejo, de lo contrario, el botón de retroceso se desactivará ... ¡y no quiere eso!

Advertencias Como puede ver, esto establece la escucha clave en la vista raíz del fragmento, y debemos enfocarlo. Si hay textos de edición involucrados (o cualquier otra vista de robo de enfoque) en su fragmento que amplíe esta clase (u otros fragmentos internos o vistas que tengan el mismo), deberá manejarlo por separado. Hay un buen artículo sobre la extensión de un EditText para perder el enfoque en una pulsación posterior.

Espero que alguien encuentre esto útil. Feliz codificacion


De acuerdo con @HaMMeRed, la respuesta aquí es pseudocódigo de cómo debería funcionar. Digamos que su actividad principal se llama BaseActivity que tiene fragmentos secundarios (como en el ejemplo de lib de SlidingMenu). Aquí están los pasos:

Primero necesitamos crear una interfaz y una clase que implemente su interfaz para tener un método genérico.

  1. Crear interfaz de clase OnBackPressedListener

    public interface OnBackPressedListener { public void doBack(); }

  2. Crear una clase que implemente las habilidades de OnBackPressedListener

    public class BaseBackPressedListener implements OnBackPressedListener { private final FragmentActivity activity; public BaseBackPressedListener(FragmentActivity activity) { this.activity = activity; } @Override public void doBack() { activity.getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); } }

  3. Desde ahora, trabajaremos en nuestro código BaseActivity y sus fragmentos.

  4. Crea un oyente privado sobre tu clase BaseActivity

    protected OnBackPressedListener onBackPressedListener;

  5. Crear método para configurar el oyente en BaseActivity

    public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) { this.onBackPressedListener = onBackPressedListener; }

  6. en anular onBackPressed implementar algo por el estilo

    @Override public void onBackPressed() { if (onBackPressedListener != null) onBackPressedListener.doBack(); else super.onBackPressed();

  7. en su fragmento en onCreateView debe agregar nuestro oyente

    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { activity = getActivity(); ((BaseActivity)activity).setOnBackPressedListener(new BaseBackPressedListener(activity)); View view = ... ; //stuff with view return view; }

Ahora, cuando haga clic de nuevo en el fragmento, debería capturar su método personalizado en la parte posterior.


Debes agregar una interfaz a tu proyecto como abajo;

public interface OnBackPressed { void onBackPressed(); }

Y luego, debes implementar esta interfaz en tu fragmento;

public class SampleFragment extends Fragment implements OnBackPressed { @Override public void onBackPressed() { //on Back Pressed } }

Y puede desencadenar este evento onBackPressed en sus actividades del evento onBackPressed como se muestra a continuación;

public class MainActivity extends AppCompatActivity { @Override public void onBackPressed() { Fragment currentFragment = getSupportFragmentManager().getFragments().get(getSupportFragmentManager().getBackStackEntryCount() - 1); if (currentFragment instanceof OnBackPressed) { ((OnBackPressed) currentFragment).onBackPressed(); } super.onBackPressed(); } }


Esto es solo un pequeño código que hará el truco:

getActivity().onBackPressed();

Espero que ayude a alguien :)


Esto funcionó para mí: https://.com/a/27145007/3934111

@Override public void onResume() { super.onResume(); if(getView() == null){ return; } getView().setFocusableInTouchMode(true); getView().requestFocus(); getView().setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){ // handle back button''s click listener return true; } return false; } }); }


La solución es simple:

1) Si tiene una clase de fragmentos base que se extienden a todos los fragmentos, agregue este código a su clase, de lo contrario cree una clase de fragmentos base

/* * called when on back pressed to the current fragment that is returned */ public void onBackPressed() { // add code in super class when override }

2) En su clase de actividad, anule onBackPressed de la siguiente manera:

private BaseFragment _currentFragment; @Override public void onBackPressed() { super.onBackPressed(); _currentFragment.onBackPressed(); }

3) En su clase de Fragmento, agregue el código deseado:

@Override public void onBackPressed() { setUpTitle(); }


Nada de eso es fácil de implementar ni funcionará de manera óptima.

Los fragmentos tienen un método llamado onDetach que hará el trabajo.

@Override public void onDetach() { super.onDetach(); PUT YOUR CODE HERE }

Esto va a hacer el trabajo.


No implemente el método ft.addToBackStack (), de modo que al presionar el botón Atrás se terminará su actividad.

proAddAccount = new ProfileAddAccount(); FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.replace(R.id.fragment_container, proAddAccount); //fragmentTransaction.addToBackStack(null); fragmentTransaction.commit();


Pues lo hice así, y me funciona.

Interfaz simple

FragmentOnBackClickInterface.java

public interface FragmentOnBackClickInterface { void onClick(); }

Ejemplo de implementación

MyFragment.java

public class MyFragment extends Fragment implements FragmentOnBackClickInterface { // other stuff public void onClick() { // what you want to call onBackPressed? }

entonces simplemente anula onBackPressed en actividad

@Override public void onBackPressed() { int count = getSupportFragmentManager().getBackStackEntryCount(); List<Fragment> frags = getSupportFragmentManager().getFragments(); Fragment lastFrag = getLastNotNull(frags); //nothing else in back stack || nothing in back stack is instance of our interface if (count == 0 || !(lastFrag instanceof FragmentOnBackClickInterface)) { super.onBackPressed(); } else { ((FragmentOnBackClickInterface) lastFrag).onClick(); } } private Fragment getLastNotNull(List<Fragment> list){ for (int i= list.size()-1;i>=0;i--){ Fragment frag = list.get(i); if (frag != null){ return frag; } } return null; }


Respuesta muy corta y dulce:

getActivity().onBackPressed();

Explicación de todo el escenario de mi caso:

Tengo FragmentA en MainActivity, estoy abriendo FragmentB desde FragmentA (FragmentB es hijo o fragmento anidado de FragmentA)

Fragment duedateFrag = new FragmentB(); FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.replace(R.id.container_body, duedateFrag); ft.addToBackStack(null); ft.commit();

Ahora, si desea ir a FragmentA desde FragmentB, simplemente puede poner getActivity().onBackPressed(); en FragmentB.


Si deseara ese tipo de funcionalidad, tendría que anularla en su actividad y luego agregar una interfaz YourBackPressed a todos sus fragmentos, a los que llama en el fragmento relevante cada vez que se presiona el botón Atrás.

Edit: me gustaría añadir mi respuesta anterior.

Si tuviera que hacer esto hoy, usaría una transmisión, o posiblemente una transmisión ordenada si esperaba que otros paneles se actualizaran al unísono al panel de contenido principal / principal.

LocalBroadcastManager en la biblioteca de soporte puede ayudarte con esto, y solo envías la transmisión en onBackPressed y te suscribes en los fragmentos que te interesan. Creo que la mensajería es una implementación más desacoplada y se escalaría mejor, por lo que ahora sería mi recomendación oficial de implementación. Simplemente use la acción del Intent como filtro para su mensaje. envíe su ACTION_BACK_PRESSED recién creado, envíelo desde su actividad y escúchelo en los fragmentos relevantes.


Si usa EventBus, es probablemente una solución mucho más simple:

En tu Fragmento:

@Override public void onAttach(Activity activity) { super.onAttach(activity); EventBus.getDefault().register(this); } @Override public void onDetach() { super.onDetach(); EventBus.getDefault().unregister(this); } // This method will be called when a MessageEvent is posted public void onEvent(BackPressedMessage type){ getSupportFragmentManager().popBackStack(); }

y en tu clase de actividad puedes definir:

@Override public void onStart() { super.onStart(); EventBus.getDefault().register(this); } @Override public void onStop() { EventBus.getDefault().unregister(this); super.onStop(); } // This method will be called when a MessageEvent is posted public void onEvent(BackPressedMessage type){ super.onBackPressed(); } @Override public void onBackPressed() { EventBus.getDefault().post(new BackPressedMessage(true)); }

BackPressedMessage.java es solo un objeto POJO

Esto es súper limpio y no hay problemas de interfaz / implementación.


Simplemente agregue addToBackStack mientras realiza la transición entre sus fragmentos como se muestra a continuación:

fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();

Si escribe addToBackStack(null) , lo manejará por sí mismo, pero si le addToBackStack(null) una etiqueta, debe manejarlo manualmente.


esta es mi solucion

en MyActivity.java:

public interface OnBackClickListener { boolean onBackClick(); } private OnBackClickListener onBackClickListener; public void setOnBackClickListener(OnBackClickListener onBackClickListener) { this.onBackClickListener = onBackClickListener; } @Override public void onBackPressed() { if (onBackClickListener != null && onBackClickListener.onBackClick()) { return; } super.onBackPressed(); }

y en Fragmento:

((MyActivity) getActivity()).setOnBackClickListener(new MyActivity.OnBackClickListener() { @Override public boolean onBackClick() { if (condition) { return false; } // some codes return true; } });


onBackPressed() hace que los fragmentos se separen de la actividad.

Según la respuesta de @Sterling Díaz, creo que tiene razón. PERO alguna situación estará mal. (ej. Rotar pantalla)

Por lo tanto, creo que podríamos detectar si se está isRemoving() para alcanzar los objetivos.

Puede escribirlo en onDetach() o onDestroyView() . Eso es trabajo.

@Override public void onDetach() { super.onDetach(); if(isRemoving()){ // onBackPressed() } } @Override public void onDestroyView() { super.onDestroyView(); if(isRemoving()){ // onBackPressed() } }


onBackPressed esta manera anular onBackPressed en la Actividad. Todos los FragmentTransaction son addToBackStack antes de confirmar:

@Override public void onBackPressed() { int count = getFragmentManager().getBackStackEntryCount(); if (count == 0) { super.onBackPressed(); //additional code } else { getFragmentManager().popBackStack(); } }


Fragmento: Haz un BaseFragment colocando un método:

public boolean onBackPressed();

Actividad:

@Override public void onBackPressed() { List<Fragment> fragments = getSupportFragmentManager().getFragments(); if (fragments != null) { for (Fragment fragment : fragments) { if (!fragment.isVisible()) continue; if (fragment instanceof BaseFragment && ((BaseFragment) fragment).onBackPressed()) { return; } } } super.onBackPressed(); }

Su actividad se ejecutará sobre los fragmentos adjuntos y visibles y llamará a onBackPressed () en cada uno de ellos y abortará si uno de ellos devuelve "verdadero" (lo que significa que se ha manejado, por lo que no hay más acciones)


Solo sigue estos pasos:

Siempre al agregar un fragmento,

fragmentTransaction.add(R.id.fragment_container, detail_fragment, "Fragment_tag").addToBackStack(null).commit();

Luego, en la actividad principal, anule onBackPressed()

if (getSupportFragmentManager().getBackStackEntryCount() > 0) { getSupportFragmentManager().popBackStack(); } else { finish(); }

Para manejar el botón de retroceso en su aplicación,

Fragment f = getActivity().getSupportFragmentManager().findFragmentByTag("Fragment_tag"); if (f instanceof FragmentName) { if (f != null) getActivity().getSupportFragmentManager().beginTransaction().remove(f).commit() }

¡Eso es!


Clase pública MyActivity extiende la actividad {

protected OnBackPressedListener onBackPressedListener; public interface OnBackPressedListener { void doBack(); } public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) { this.onBackPressedListener = onBackPressedListener; } @Override public void onBackPressed() { if (onBackPressedListener != null) onBackPressedListener.doBack(); else super.onBackPressed(); } @Override protected void onDestroy() { onBackPressedListener = null; super.onDestroy(); }

}

en su fragmento agregue lo siguiente, no se olvide de implementar la interfaz de mainactivity.

public class MyFragment extends Framgent implements MyActivity.OnBackPressedListener { @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); ((MyActivity) getActivity()).setOnBackPressedListener(this); } @Override public void doBack() { //BackPressed in activity will call this; } }


He utilizado otro enfoque de la siguiente manera:

  • Un autobús de eventos Otto para comunicarse entre la Actividad y sus Fragmentos.
  • Una pila en la actividad que contiene acciones de retroceso personalizadas envueltas en un Runnablearchivo que define el fragmento
  • Cuando onBackPressedse llama en la Actividad de control, muestra la acción de retroceso personalizada más reciente y la ejecuta Runnable. Si no hay nada en la pila, super.onBackPressed()se llama por defecto

El enfoque completo con código de ejemplo se incluye here como una respuesta a esta otra pregunta SO .


Mejor solución,

import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v7.app.AppCompatActivity; public class BaseActivity extends AppCompatActivity { @Override public void onBackPressed() { FragmentManager fm = getSupportFragmentManager(); for (Fragment frag : fm.getFragments()) { if (frag == null) { super.onBackPressed(); finish(); return; } if (frag.isVisible()) { FragmentManager childFm = frag.getChildFragmentManager(); if (childFm.getFragments() == null) { super.onBackPressed(); finish(); return; } if (childFm.getBackStackEntryCount() > 0) { childFm.popBackStack(); return; } else { fm.popBackStack(); if (fm.getFragments().size() <= 1) { finish(); } return; } } } } }


Ok chicos, finalmente encontré una buena solución.

En su onCreate () en su actividad que contiene sus fragmentos, agregue un oyente de cambio de backstack así:

fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() { @Override public void onBackStackChanged() { List<Fragment> f = fragmentManager.getFragments(); //List<Fragment> f only returns one value Fragment frag = f.get(0); currentFragment = frag.getClass().getSimpleName(); } });

(La adición de mi fragmenManager se declara en las actividades O Ahora, cada vez que cambies el fragmento, el fragmento actual. La cadena se convertirá en el nombre del fragmento actual. Luego, en las actividades enBackPressed () puedes controlar las acciones de tu botón Atrás como sigue:

@Override public void onBackPressed() { switch (currentFragment) { case "FragmentOne": // your code here return; case "FragmentTwo": // your code here return; default: fragmentManager.popBackStack(); // default action for any other fragment (return to previous) } }

Puedo confirmar que este método funciona para mí.


Tuve el mismo problema y creé un nuevo oyente para él y lo utilicé en mis fragmentos.

1 - Su actividad debe tener una interfaz de escucha y una lista de escuchas en ella.

2 - Debes implementar métodos para agregar y eliminar los oyentes.

3 - Debes anular el método onBackPressed para verificar que cualquiera de los oyentes use la tecla de retroceso o no

public class MainActivity ... { /** * Back press listener list. Used for notifying fragments when onBackPressed called */ private Stack<BackPressListener> backPressListeners = new Stack<BackPressListener>(); ... /** * Adding new listener to back press listener stack * @param backPressListener */ public void addBackPressListener(BackPressListener backPressListener) { backPressListeners.add(backPressListener); } /** * Removing the listener from back press listener stack * @param backPressListener */ public void removeBackPressListener(BackPressListener backPressListener) { backPressListeners.remove(backPressListener); } // Overriding onBackPressed to check that is there any listener using this back press @Override public void onBackPressed() { // checks if is there any back press listeners use this press for(BackPressListener backPressListener : backPressListeners) { if(backPressListener.onBackPressed()) return; } // if not returns in the loop, calls super onBackPressed super.onBackPressed(); } }

4 - Su fragmento debe implementar la interfaz para la prensa de vuelta

5 - Es necesario agregar el fragmento como un oyente para la prensa inversa

6 - Debes devolver true desde onBackPressed si el fragmento usa esta tecla de retroceso.

7 - IMPORTANTE - Debe eliminar el fragmento de la lista en Destruir

public class MyFragment extends Fragment implements MainActivity.BackPressListener { ... @Override public void onAttach(Activity activity) { super.onCreate(savedInstanceState); // adding the fragment to listener list ((MainActivity) activity).addBackPressListener(this); } ... @Override public void onDestroy() { super.onDestroy(); // removing the fragment from the listener list ((MainActivity) getActivity()).removeBackPressListener(this); } ... @Override public boolean onBackPressed() { // you should check that if this fragment is the currently used fragment or not // if this fragment is not used at the moment you should return false if(!isThisFragmentVisibleAtTheMoment) return false; if (isThisFragmentUsingBackPress) { // do what you need to do return true; } return false; } }

Se utiliza una pila en lugar de ArrayList para poder comenzar desde el último fragmento. También puede haber un problema al agregar fragmentos a la pila posterior. Por lo tanto, debe verificar que el fragmento esté visible o no mientras se usa la tecla de retroceso. De lo contrario, uno de los fragmentos utilizará el evento y el último fragmento no se cerrará en la prensa trasera.

Espero que esto resuelva el problema para todos.


en mainActivity

protected DrawerHomeActivity.OnBackPressedListener onBackPressedListener; public interface OnBackPressedListener { void doBack(); } public void setOnBackPressedListener(DrawerHomeActivity.OnBackPressedListener onBackPressedListener) { this.onBackPressedListener = onBackPressedListener; } @Override public void onBackPressed() { if (onBackPressedListener != null) { onBackPressedListener.doBack(); } else super.onBackPressed(); }

en el fragmento implementar la actividad base / fragmento como

implements DrawerHomeActivity.OnBackPressedListener

DraweHomeActivity es mi actividad base escribir

((DrawerHomeActivity) getActivity()).setOnBackPressedListener(this);

y crea método doBack

@Override public void doBack() { //call base fragment }


En el ciclo de vida de la actividad, siempre el botón de retroceso de Android trata con las transacciones de FragmentManager cuando usamos FragmentActivity o AppCompatActivity.

Para manejar el backstack no necesitamos manejar su conteo de backstack o etiquetar nada, pero debemos mantener el enfoque al agregar o reemplazar un fragmento. Por favor encuentre los siguientes fragmentos para manejar los casos del botón Atrás,

public void replaceFragment(Fragment fragment) { FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); if (!(fragment instanceof HomeFragment)) { transaction.addToBackStack(null); } transaction.replace(R.id.activity_menu_fragment_container, fragment).commit(); }

Aquí, no agregaré la pila de nuevo para el fragmento de mi casa porque es la página de inicio de mi aplicación. Si agrega addToBackStack a HomeFragment, la aplicación esperará para eliminar todo el marco en la actividad, entonces obtendremos una pantalla en blanco, así que mantengo la siguiente condición:

if (!(fragment instanceof HomeFragment)) { transaction.addToBackStack(null); }

Ahora, puede ver el fragmento agregado previamente en la actividad y la aplicación se cerrará cuando llegue a HomeFragment. También puedes mirar en los siguientes fragmentos.

@Override public void onBackPressed() { if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) { closeDrawer(); } else { super.onBackPressed(); } }


Sé que es demasiado tarde, pero tuve el mismo problema la semana pasada. Ninguna de las respuestas me ayudó. Entonces estaba jugando con el código y esto funcionó, ya que ya había agregado los fragmentos.

En su Actividad, establezca una OnPageChangeListenerpara ViewPagerque sepa cuándo el usuario está en la segunda actividad. Si está en la segunda actividad, haga un booleano truecomo sigue:

mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); // Set up the ViewPager with the sections adapter. mViewPager = (ViewPager) findViewById(R.id.pager); mViewPager.setAdapter(mSectionsPagerAdapter); mViewPager.setCurrentItem(0); mViewPager.addOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageSelected(int position) { // TODO Auto-generated method stub mSectionsPagerAdapter.instantiateItem(mViewPager, position); if(position == 1) inAnalytics = true; else if(position == 0) inAnalytics = false; } @Override public void onPageScrolled(int position, float arg1, int arg2) { // TODO Auto-generated method stub } @Override public void onPageScrollStateChanged(int arg0) { // TODO Auto-generated method stub } });

Ahora compruebe el booleano cuando se presione el botón Atrás y configure el elemento actual en su primer Fragmento:

@Override public void onBackPressed() { if(inAnalytics) mViewPager.setCurrentItem(0, true); else super.onBackPressed(); }


Su justo sencilla si tienen una actividad A y haces 3 fragmentos como B, C y D.Now si se encuentra en el fragmento B o C y onBackPressedque desea mover el Fragmento D .A continuación, cada vez que usted tiene que apenas Reemplazar el onBackPressed()método en el Actividad principal A y también cuando saltas a cualquier fragmento, luego pasas un TAG o nombre de ese fragmento por el cual reconociste ese fragmento en la Actividad principal A.

Estoy dando el ejemplo de aquel por el cual puedes entenderlo fácilmente ...

if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction().add(R.id.container, new C_fragment(),"xyz").commit(); }

o si se está moviendo del fragmento B al fragmento C ... y al presionar hacia atrás, desea ingresar el Fragmento D ... como a continuación

btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { getActivity().getSupportFragmentManager().beginTransaction().add(R.id.container, new C_frament(), "xyz").commit(); ((ActionBarActivity) getActivity()).getSupportActionBar().setTitle("Fragment C"); } });

Ahora solo tiene que anular el método onBackPressed () en la actividad principal ... como a continuación ...

@Override public void onBackPressed() { FragmentManager fragmentManager =getSupportFragmentManager(); if (((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")) != null && ((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")).isVisible()) { Fragment fragment = new D_Fragment(); fragmentManager.beginTransaction().replace(R.id.container, fragment).commit(); getSupportActionBar().setTitle("D fragment "); } else { super.onBackPressed(); } }


@Override public void onResume() { super.onResume(); getView().setFocusableInTouchMode(true); getView().requestFocus(); getView().setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) { // handle back button replaceFragmentToBackStack(getActivity(), WelcomeFragment.newInstance(bundle), tags); return true; } return false; } }); }