Android Fragment handle button back press

Tengo algunos fragmentos en mi actividad

[1], [2], [3], [4], [5], [6] 

Y en el botón Atrás, presione I debe regresar de [2] a [1] si el fragmento activo actual es [2], o no hacer nada de lo contrario.

¿Cuál es la mejor práctica para hacer eso?

EDITAR : la aplicación no debe volver a [2] desde [3] … [6]

Cuando esté addToBackStack() transición entre Fragmentos, llame a addToBackStack() como parte de su FragmentTransaction :

 FragmentTransaction tx = fragmentManager.beginTransation(); tx.replace( R.id.fragment, new MyFragment() ).addToBackStack( "tag" ).commit(); 

Si necesita un control más detallado (es decir, cuando algunos Fragmentos están visibles, y desea suprimir la tecla Atrás), puede configurar un OnKeyListener en la vista principal de su fragmento:

 //You need to add the following line for this solution to work; thanks skayred fragment.getView().setFocusableInTouchMode(true); fragment.getView().requestFocus(); fragment.getView().setOnKeyListener( new OnKeyListener() { @Override public boolean onKey( View v, int keyCode, KeyEvent event ) { if( keyCode == KeyEvent.KEYCODE_BACK ) { return true; } return false; } } ); 

Prefiero hacer algo como esto:

 private final static String TAG_FRAGMENT = "TAG_FRAGMENT"; private void showFragment() { final Myfragment fragment = new MyFragment(); final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.fragment, fragment, TAG_FRAGMENT); transaction.addToBackStack(null); transaction.commit(); } @Override public void onBackPressed() { final Myfragment fragment = (Myfragment) getSupportFragmentManager().findFragmentByTag(TAG_FRAGMENT); if (fragment.allowBackPressed()) { // and then you define a method allowBackPressed with the logic to allow back pressed or not super.onBackPressed(); } } 

si sobreescribe el método onKey para la vista de fragmento que va a necesitar:

  view.setFocusableInTouchMode(true); view.requestFocus(); view.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { Log.i(tag, "keyCode: " + keyCode); if( keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) { Log.i(tag, "onKey Back listener is working!!!"); getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); return true; } return false; } }); 

Use el método addToBackStack cuando reemplace un fragmento por otro:

 getFragmentManager().beginTransaction().replace(R.id.content_frame, fragment).addToBackStack("my_fragment").commit(); 

Luego, en su actividad, use el siguiente código para volver de un fragmento a otro (el anterior).

 @Override public void onBackPressed() { if (getFragmentManager().getBackStackEntryCount() > 0) { getFragmentManager().popBackStack(); } else { super.onBackPressed(); } } 

Si desea manejar el evento de tecla atrás de hardware, debe hacer el siguiente código en su método onActivityCreated () de Fragment.

También debe verificar el evento Action_Down o Action_UP. Si no va a marcar, entonces el método OnKey () llamará 2 veces.

Además, si su vista de raíz (getView ()) no contendrá el foco, entonces no funcionará. Si ha hecho clic en cualquier control, entonces nuevamente debe enfocar la vista de raíz usando getView (). RequestFocus (); Después de esto, solo onKeydown () llamará.

 getView().setFocusableInTouchMode(true); getView().requestFocus(); getView().setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { if (keyCode == KeyEvent.KEYCODE_BACK) { Toast.makeText(getActivity(), "Back Pressed", Toast.LENGTH_SHORT).show(); return true; } } return false; } }); 

Trabajando muy bien para mi

La forma más ideal de hacer esto se encuentra aquí: Fragmento: qué callback se invoca al presionar el botón Atrás y personalizarlo

 public class MyActivity extends Activity { //... //Defined in Activity class, so override @Override public void onBackPressed() { super.onBackPressed(); myFragment.onBackPressed(); } } public class MyFragment extends Fragment { //Your created method public static void onBackPressed() { //Pop Fragments off backstack and do your other checks } } 

Crear interfaces:

BackButtonHandlerInterface

 public interface BackButtonHandlerInterface { void addBackClickListener (OnBackClickListener onBackClickListener); void removeBackClickListener (OnBackClickListener onBackClickListener); } 

OnBackClickListener

 public interface OnBackClickListener { boolean onBackClick(); } 

En actividad:

 public class MainActivity extends AppCompatActivity implements BackButtonHandlerInterface { private ArrayList> backClickListenersList = new ArrayList<>(); @Override public void addBackClickListener(OnBackClickListener onBackClickListener) { backClickListenersList.add(new WeakReference<>(onBackClickListener)); } @Override public void removeBackClickListener(OnBackClickListener onBackClickListener) { for (Iterator> iterator = backClickListenersList.iterator(); iterator.hasNext();){ WeakReference weakRef = iterator.next(); if (weakRef.get() == onBackClickListener){ iterator.remove(); } } } @Override public void onBackPressed() { if(!fragmentsBackKeyIntercept()){ super.onBackPressed(); } } private boolean fragmentsBackKeyIntercept() { boolean isIntercept = false; for (WeakReference weakRef : backClickListenersList) { OnBackClickListener onBackClickListener = weakRef.get(); if (onBackClickListener != null) { boolean isFragmIntercept = onBackClickListener.onBackClick(); if (!isIntercept) isIntercept = isFragmIntercept; } } return isIntercept; } } 

En Fragmento :

 public class MyFragment extends Fragment implements OnBackClickListener{ private BackButtonHandlerInterface backButtonHandler; @Override public void onAttach(Activity activity) { super.onAttach(activity); backButtonHandler = (BackButtonHandlerInterface) activity; backButtonHandler.addBackClickListener(this); } @Override public void onDetach() { super.onDetach(); backButtonHandler.removeBackClickListener(this); backButtonHandler = null; } @Override public boolean onBackClick() { //This method handle onBackPressed()! return true or false return false; } } 

  @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){ if (mDrawerLayout.isDrawerOpen(GravityCompat.START)){ mDrawerLayout.closeDrawer(GravityCompat.START); } return true; } return false; } }); } 

O puede usar getSupportFragmentManager().getBackStackEntryCount() para verificar qué hacer:

 @Override public void onBackPressed() { logger.d("@@@@@@ back stack entry count : " + getSupportFragmentManager().getBackStackEntryCount()); if (getSupportFragmentManager().getBackStackEntryCount() != 0) { // only show dialog while there's back stack entry dialog.show(getSupportFragmentManager(), "ConfirmDialogFragment"); } else if (getSupportFragmentManager().getBackStackEntryCount() == 0) { // or just go back to main activity super.onBackPressed(); } } 

Si administra el flujo de agregar a la stack de respaldo cada transacción, puede hacer algo como esto para mostrar el fragmento anterior cuando el usuario presiona el botón Atrás (también puede asignar el botón de inicio).

 @Override public void onBackPressed() { if (getFragmentManager().getBackStackEntryCount() > 0) getFragmentManager().popBackStack(); else super.onBackPressed(); } 

Estoy trabajando con SlidingMenu y Fragment, presento mi caso aquí y espero que ayude a alguien.

Lógica cuando se presiona la tecla [Atrás]:

  1. Cuando se muestra SlidingMenu, ciérrelo, no hay más cosas que hacer.
  2. O cuando se muestre el 2 ° (o más) Fragmentos, vuelva al Fragmento anterior y no tenga más cosas que hacer.
  3. SlidingMenu no se muestra, el Fragmento actual es # 0, la clave original [Atrás] sí lo hace.

     public class Main extends SherlockFragmentActivity { private SlidingMenu menu=null; Constants.VP=new ViewPager(this); //Some stuff... @Override public void onBackPressed() { if(menu.isMenuShowing()) { menu.showContent(true); //Close SlidingMenu when menu showing return; } else { int page=Constants.VP.getCurrentItem(); if(page>0) { Constants.VP.setCurrentItem(page-1, true); //Show previous fragment until Fragment#0 return; } else {super.onBackPressed();} //If SlidingMenu is not showing and current Fragment is #0, do the original [Back] key does. In my case is exit from APP } } } 

Esta es una solución muy buena y confiable: http://vinsol.com/blog/2014/10/01/handling-back-button-press-inside-fragments/

El tipo ha creado un fragmento abstracto que maneja el comportamiento de backPress y está cambiando entre los fragmentos activos usando el patrón de estrategia.

Para algunos de ustedes, tal vez haya un pequeño inconveniente en la clase abstracta …

En breve, la solución del enlace es la siguiente:

 // Abstract Fragment handling the back presses public abstract class BackHandledFragment extends Fragment { protected BackHandlerInterface backHandlerInterface; public abstract String getTagText(); public abstract boolean onBackPressed(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if(!(getActivity() instanceof BackHandlerInterface)) { throw new ClassCastException("Hosting activity must implement BackHandlerInterface"); } else { backHandlerInterface = (BackHandlerInterface) getActivity(); } } @Override public void onStart() { super.onStart(); // Mark this fragment as the selected Fragment. backHandlerInterface.setSelectedFragment(this); } public interface BackHandlerInterface { public void setSelectedFragment(BackHandledFragment backHandledFragment); } } 

Y el uso en la actividad:

 // BASIC ACTIVITY CODE THAT LETS ITS FRAGMENT UTILIZE onBackPress EVENTS // IN AN ADAPTIVE AND ORGANIZED PATTERN USING BackHandledFragment public class TheActivity extends FragmentActivity implements BackHandlerInterface { private BackHandledFragment selectedFragment; @Override public void onBackPressed() { if(selectedFragment == null || !selectedFragment.onBackPressed()) { // Selected fragment did not consume the back press event. super.onBackPressed(); } } @Override public void setSelectedFragment(BackHandledFragment selectedFragment) { this.selectedFragment = selectedFragment; } } 

Código de trabajo:

 package com.example.keralapolice; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentManager.OnBackStackChangedListener; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; public class ChiefFragment extends Fragment { View view; // public OnBackPressedListener onBackPressedListener; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle args) { view = inflater.inflate(R.layout.activity_chief, container, false); getActivity().getActionBar().hide(); view.setFocusableInTouchMode(true); view.requestFocus(); view.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { Log.i(getTag(), "keyCode: " + keyCode); if (keyCode == KeyEvent.KEYCODE_BACK) { getActivity().getActionBar().show(); Log.i(getTag(), "onKey Back listener is working!!!"); getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); // String cameback="CameBack"; Intent i = new Intent(getActivity(), home.class); // i.putExtra("Comingback", cameback); startActivity(i); return true; } else { return false; } } }); return view; } } 

Creo que la manera más fácil es crear una interfaz, y en la comprobación de actividad si el fragmento es del tipo de interfaz, y si es así, llame a su método para manejar el pop. Aquí está la interfaz para implementar en el fragmento.

 public interface BackPressedFragment { // Note for this to work, name AND tag must be set anytime the fragment is added to back stack, eg // getActivity().getSupportFragmentManager().beginTransaction() // .replace(R.id.fragment_container, MyFragment.newInstance(), "MY_FRAG_TAG") // .addToBackStack("MY_FRAG_TAG") // .commit(); // This is really an override. Should call popBackStack itself. void onPopBackStack(); } 

He aquí cómo implementarlo.

 public class MyFragment extends Fragment implements BackPressedFragment @Override public void onPopBackStack() { /* Your code goes here, do anything you want. */ getActivity().getSupportFragmentManager().popBackStack(); } 

Y en su Actividad, cuando maneja el pop (probablemente en onBackPressed y onOptionsItemSelected), abra la backstack usando este método:

 public void popBackStack() { FragmentManager fm = getSupportFragmentManager(); // Call current fragment's onPopBackStack if it has one. String fragmentTag = fm.getBackStackEntryAt(fm.getBackStackEntryCount() - 1).getName(); Fragment currentFragment = getSupportFragmentManager().findFragmentByTag(fragmentTag); if (currentFragment instanceof BackPressedFragment) ((BackPressedFragment)currentFragment).onPopBackStack(); else fm.popBackStack(); } 
  rootView.setFocusableInTouchMode(true); rootView.requestFocus(); rootView.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { Fragment NameofFragment = new NameofFragment; FragmentTransaction transaction=getFragmentManager().beginTransaction(); transaction.replace(R.id.frame_container,NameofFragment); transaction.commit(); return true; } return false; } }); return rootView; 

Creamos una pequeña biblioteca para manejar la retroimpresión en múltiples fragmentos y / o en la actividad. El uso es tan simple como agregar dependencia en su archivo gradle:

 compile 'net.skoumal.fragmentback:fragment-back:0.1.0' 

Deje que su fragmento implemente la interfaz BackFragment :

 public abstract class MyFragment extends Fragment implements BackFragment { public boolean onBackPressed() { // -- your code -- // return true if you want to consume back-pressed event return false; } public int getBackPriority() { return NORMAL_BACK_PRIORITY; } } 

Notifique sus fragmentos sobre las prensas traseras:

 public class MainActivity extends AppCompatActivity { @Override public void onBackPressed() { // first ask your fragments to handle back-pressed event if(!BackFragmentHelper.fireOnBackPressedEvent(this)) { // lets do the default back action if fragments don't consume it super.onBackPressed(); } } } 

Para más detalles y otros casos de uso, visite la página de GitHub:

https://github.com/skoumalcz/fragment-back

Puede usar from getActionBar().setDisplayHomeAsUpEnabled() :

 @Override public void onBackStackChanged() { int backStackEntryCount = getFragmentManager().getBackStackEntryCount(); if(backStackEntryCount > 0){ getActionBar().setDisplayHomeAsUpEnabled(true); }else{ getActionBar().setDisplayHomeAsUpEnabled(false); } } 

Agregue addToBackStack () para fragmentar la transacción y luego use el código a continuación para Implementar la navegación hacia atrás para los fragmentos

 getSupportFragmentManager().addOnBackStackChangedListener( new FragmentManager.OnBackStackChangedListener() { public void onBackStackChanged() { // Update your UI here. } }); 

si está utilizando FragmentActivity. entonces haz como este

primero llama Esto dentro de tu Fragmento.

 public void callParentMethod(){ getActivity().onBackPressed(); } 

y luego, llame onBackPressed método onBackPressed en el lado de su clase primaria FragmentActivity .

 @Override public void onBackPressed() { //super.onBackPressed(); //create a dialog to ask yes no question whether or not the user wants to exit ... } 

Agrega este código en tu Actividad

@Anular

 public void onBackPressed() { if (getFragmentManager().getBackStackEntryCount() == 0) { super.onBackPressed(); } else { getFragmentManager().popBackStack(); } } 

Y agrega esta línea en tu Fragmento antes de confirmar ()

ft.addToBackStack (“Cualquier nombre”);

Para aquellos que usan fragmentos estáticos

En un caso si tienes un fragmento estático, entonces sería preferible. Haz un objeto instancia de tu fragmento

 private static MyFragment instance=null; 

en onCreate () de MyFragment inicializa esa instancia

  instance=this; 

también hacer una función para obtener Instancia

  public static MyFragment getInstance(){ return instance; } 

también hacer funciones

 public boolean allowBackPressed(){ if(allowBack==true){ return true; } return false; } //allowBack is a boolean variable that will be set to true at the action //where you want that your backButton should not close activity. In my case I open //Navigation Drawer then I set it to true. so when I press backbutton my //drawer should be get closed public void performSomeAction(){ //.. Your code ///Here I have closed my drawer } 

En tu actividad puedes hacer

 @Override public void onBackPressed() { if (MyFragment.getInstance().allowBackPressed()) { MyFragment.getInstance().performSomeAction(); } else{ super.onBackPressed(); } } 

en la clase de fragmento ponga este código para el evento de vuelta:

  rootView.setFocusableInTouchMode(true); rootView.requestFocus(); rootView.setOnKeyListener( new OnKeyListener() { @Override public boolean onKey( View v, int keyCode, KeyEvent event ) { if( keyCode == KeyEvent.KEYCODE_BACK ) { FragmentManager fragmentManager = getFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.frame_container, new Book_service_provider()).commit(); return true; } return false; } } ); 

Después de ver todas las soluciones, me di cuenta de que hay una solución mucho más simple.

En la actividad onBackPressed () que hospeda todos sus fragmentos, busque el fragmento que desea evitar presionar nuevamente. Entonces, si lo encuentras, solo regresa. Entonces popBackStack nunca sucederá para este fragmento.

  @Override public void onBackPressed() { Fragment1 fragment1 = (Fragment1) getFragmentManager().findFragmentByTag(“Fragment1”); if (fragment1 != null) return; if (getFragmentManager().getBackStackEntryCount() > 0){ getFragmentManager().popBackStack(); } } 

Verificar la backstack funciona perfectamente


 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { if (getFragmentManager().getBackStackEntryCount() == 1) { // DO something here since there is only one fragment left // Popping a dialog asking to quit the application return false; } } return super.onKeyDown(keyCode, event); } 

En tu método oncreateView () necesitas escribir este código y en la condición KEYCODE_BACk puedes escribir la funcionalidad que quieras

 View v = inflater.inflate(R.layout.xyz, container, false); //Back pressed Logic for fragment v.setFocusableInTouchMode(true); v.requestFocus(); v.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { if (keyCode == KeyEvent.KEYCODE_BACK) { getActivity().finish(); Intent intent = new Intent(getActivity(), MainActivity.class); startActivity(intent); return true; } } return false; } });