Fragmentos no siempre se reemplazan cuando se utiliza el botón Atrás

Estoy usando las pestañas de la barra de acciones porque necesito que los elementos de navegación estén en cada página. Estoy utilizando ActionBarSherlock para compatibilidad hacia atrás (mínimo API 8, API de destino 17). Mi MainActivity extiende SherlockFragmentActivity. En mi onCreate() para eso, tengo

 ActionBar actionBar = getSupportActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); actionBar.setDisplayShowTitleEnabled(true); Tab tab1 = actionBar.newTab().setText("My Pages") .setTabListener(new MyPagesFragment()); Tab tab2 = actionBar.newTab().setText("Search") .setTabListener(new SearchFragment()); Tab tab3 = actionBar.newTab().setText("About") .setTabListener(new AboutFragment()); // Start with the second tab selected. actionBar.addTab(tab1, 0, false); actionBar.addTab(tab2, 1, true); actionBar.addTab(tab3, 2, false); 

Todos los fragmentos de pestañas son SherlockListFragments que implementan ActionBar.TabListener y hacen esto

 @Override public void onTabSelected(Tab tab, FragmentTransaction ft) { ft.replace(android.R.id.content, this, "mypages"); } @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) { ft.remove(this); } @Override public void onTabReselected(Tab tab, FragmentTransaction ft) { // Force a complete reload. onTabSelected(tab, ft); } 

La página de búsqueda tiene un EditText y utiliza su valor en un AsyncTask para obtener datos de una API y agregarla a una base de datos SQLite, antes de llamar

 ((MainActivity) getActivity()).showDetailView(responseCode); 

Para mostrar los detalles , que es un método en mi MainActivity como sigue:

 protected void showDetailView(long codeID) { SherlockFragment detailFragment = new DetailFragment(); Bundle args = new Bundle(); args.putLong("codeID", codeID); detailFragment.setArguments(args); FragmentManager manager = getSupportFragmentManager(); FragmentTransaction ft = manager.beginTransaction(); ft.replace(android.R.id.content, detailFragment); ft.addToBackStack(null); ft.commit(); } 

DetailFragment es un SherlockFragment que utiliza getArguments() para recuperar el codeID–

 Bundle args = getArguments(); if (null != args) { codeRowID = args.getLong("codeID"); } 

–y lee los datos coincidentes de la base de datos para mostrarlos. Dichos datos a menudo contienen enlaces a más detalles, haciendo clic en que hace que showDetailView se vuelva a llamar con el nuevo codeID.

MyPages es una lista de todas las páginas de detalles en caché, y también llama a showDetailView:

 @Override public void onItemClick(AdapterView<?> parent, View v, int position, long id) { ((MainActivity) getActivity()).showDetailView(pages[position].codeId); } 

En el futuro, esto parece funcionar bien. Sin embargo, cuando uso el botón de retroceso, a veces los fragmentos se pegan alrededor, por lo que todavía están visibles detrás del fragmento restaurado. ¿Cómo puedo detener esto?


Creo que el problema es tal vez que las pestañas no se están añadiendo a la backstack? Pero cuando trato de hacer eso, me lanzan una excepción diciéndome que no se pueden agregar a la backstack, así que no entiendo cómo se supone que debes manejar esto. No entiendo por qué esta cosa, que parece ser debe ser una cosa de navegación increíblemente básica que mucha gente quiere hacer – la tecla de regreso ha estado en todos los teléfonos Android y la tabla que he visto, físicamente o de software ! –aparentemente no tiene solución conocida. ¿Acaso he malinterpretado fundamentalmente su uso? ¿No se supone que los fragmentos se utilizan en esta situación? ¿De qué otra forma puede hacer elementos de navegación persistentes sin repetir el mismo código en cada página?


Registro – inicio de la aplicación –

 07-20 23:33:49.521: D/NAVIGATION_TRACE(7425): MAIN - onCreate 07-20 23:33:50.013: D/NAVIGATION_TRACE(7425): SEARCH - onTabSelected 07-20 23:33:50.021: D/NAVIGATION_TRACE(7425): SEARCH - onCreateView 07-20 23:33:50.060: D/NAVIGATION_TRACE(7425): SEARCH - onActivityCreated 07-20 23:33:50.060: D/NAVIGATION_TRACE(7425): MAIN - onResume 

Buscar ahora visible. Buscar un elemento para mostrar la vista de detalle –

 07-20 23:34:52.123: D/NAVIGATION_TRACE(7425): SEARCH - handleResponseCode 07-20 23:34:52.123: D/NAVIGATION_TRACE(7425): MAIN - showDetailView - 31 

Detalle ahora visible; Buscar ido. Haga clic en mi pestaña de páginas –

 07-20 23:35:37.787: D/NAVIGATION_TRACE(7425): SEARCH - onTabUnselected 07-20 23:35:37.787: D/NAVIGATION_TRACE(7425): MYPAGES - onTabSelected 07-20 23:35:37.826: D/NAVIGATION_TRACE(7425): MYPAGES - onCreateView 07-20 23:35:37.873: D/NAVIGATION_TRACE(7425): MYPAGES - onActivityCreated 

MyPages ahora visible; Detalle ido. Haga clic en el botón Atrás –

 07-20 23:36:12.130: D/NAVIGATION_TRACE(7425): SEARCH - onCreateView 07-20 23:36:12.201: D/NAVIGATION_TRACE(7425): SEARCH - onActivityCreated 

Buscar y Mis páginas ahora se muestran.


Actividad principal:

 public class MainActivity extends SherlockFragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d("NAVIGATION_TRACE", "MAIN - onCreate"); ActionBar actionBar = getSupportActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); actionBar.setDisplayShowTitleEnabled(true); Tab tab1 = actionBar.newTab().setText("My Pages") .setTabListener(new TabListener<MyPagesFragment>( this, "mypages", MyPagesFragment.class)); Tab tab2 = actionBar.newTab().setText("Search") .setTabListener(new TabListener<SearchFragment>( this, "search", SearchFragment.class)); Tab tab3 = actionBar.newTab().setText("About") .setTabListener(new TabListener<AboutFragment>( this, "about", AboutFragment.class)); // Start with the second tab selected. actionBar.addTab(tab1, 0, false); actionBar.addTab(tab2, 1, true); actionBar.addTab(tab3, 2, false); } @Override public void onBackPressed() { FragmentManager fm = getSupportFragmentManager(); if (0 < fm.getBackStackEntryCount()) { super.onBackPressed(); } else { // prompt to quit AlertDialog.Builder alertErrorResponse = new AlertDialog.Builder(this); alertErrorResponse.setMessage("Close app?"); alertErrorResponse.setNegativeButton("Cancel", null); alertErrorResponse.setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }); alertErrorResponse.show(); } } public void showDetailView(long codeID) { Log.d("NAVIGATION_TRACE", "MAIN - showDetailView - "+String.valueOf(codeID)); lastShownCode = codeID; FragmentManager manager = getSupportFragmentManager(); FragmentTransaction ft = manager.beginTransaction(); SherlockFragment detailFragment = new DetailFragment(); Bundle args = new Bundle(); args.putLong("codeID", codeID); detailFragment.setArguments(args); ft.replace(android.R.id.content, detailFragment, "details"); ft.addToBackStack(null); ft.commit(); } public class TabListener<T extends SherlockListFragment> implements ActionBar.TabListener { private final SherlockFragmentActivity mActivity; private final String mTag; private final Class<T> mClass; private SherlockListFragment mFragment; public TabListener (SherlockFragmentActivity activity, String tag, Class<T> clz) { Log.d("NAVIGATION_TRACE", "TabListener - "+tag+" - "+clz.getCanonicalName()); mActivity = activity; mTag = tag; mClass = clz; FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction(); mFragment = (SherlockListFragment) mActivity.getSupportFragmentManager().findFragmentByTag(mTag); if (mFragment != null && !mFragment.isDetached()) { Log.d("NAVIGATION_TRACE", "DETACH - "+mTag); removeDetail(ft); ft.detach(mFragment); } ft.commit(); } public void clearBackStack() { Log.d("NAVIGATION_TRACE", "clearBackStack - "+mTag); FragmentManager fm = mActivity.getSupportFragmentManager(); if (null != fm && 0 < fm.getBackStackEntryCount()) { fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); } } @Override public void onTabSelected(Tab tab, FragmentTransaction ft) { Log.d("NAVIGATION_TRACE", "onTabSelected - "+mTag); clearBackStack(); ft = mActivity.getSupportFragmentManager().beginTransaction(); if (mFragment == null) { Log.d("NAVIGATION_TRACE", "ADD/SHOW - "+mClass.getName()); removeDetail(ft); mFragment = (SherlockListFragment) SherlockListFragment.instantiate(mActivity, mClass.getName()); ft.add(android.R.id.content, mFragment, mTag); ft.commit(); } else { Log.d("NAVIGATION_TRACE", "ATTACH/SHOW - "+mClass.getName()); removeDetail(ft); ft.attach(mFragment); ft.show(mFragment); ft.commit(); } } @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) { Log.d("NAVIGATION_TRACE", "onTabUnselected - "+mTag); ft = mActivity.getSupportFragmentManager().beginTransaction(); if (null != mFragment) { Log.d("NAVIGATION_TRACE", "HIDE/DETACH - "+mTag); removeDetail(ft); ft.hide(mFragment); ft.detach(mFragment); ft.commitAllowingStateLoss(); } } @Override public void onTabReselected(Tab tab, FragmentTransaction ft) { } public void removeDetail(FragmentTransaction ft) { SherlockFragment detailFragment = (SherlockFragment) mActivity.getSupportFragmentManager().findFragmentByTag("details"); if (null != detailFragment && !detailFragment.isDetached()) { Log.d("NAVIGATION_TRACE", "DETACH - details"); ft.detach(detailFragment); } } } } 

Ejemplo de fragmento – MyPagesFragment:

 public class MyPagesFragment extends SherlockListFragment implements OnItemClickListener { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.d("NAVIGATION_TRACE", "MYPAGES - onCreateView"); View view = inflater.inflate(R.layout.mypages, null); // code to set up list adapter here } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Log.d("NAVIGATION_TRACE", "MYPAGES - onActivityCreated"); getListView().setOnItemClickListener(this); } @Override public void onItemClick(AdapterView<?> parent, View v, int position, long id) { Log.d("NAVIGATION_TRACE", "MYPAGES - onItemClick"); ((MainActivity) getActivity()).showDetailView(pages[position].codeId); } } 

DetalleFragmento

 public class DetailFragment extends SherlockFragment implements OnItemClickListener { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.detail, null); // bunch of display / list set up code goes here return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); lvLinks.setOnItemClickListener(this); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // Details page can open other details pages: ((MainActivity) getActivity()).showDetailView(pages[position].id); } } 

Nota: Los cambios añadidos se hicieron a raíz de una respuesta de Sheldon (que parece haber borrado su respuesta y comentarios), por lo que el código TabListener cambió entre la sección original y el código posteado más tarde.

En la actualidad, he hackeado una solución mediante el vaciado de la backstack en cada selección de pestañas, y el tratamiento de nuevo en una pestaña superior como una solicitud de salida de la aplicación, que está bien, supongo, pero me gustaría que los usuarios puedan mantener Retroceder a través de las pestañas si esto es posible (porque de esa manera, por ejemplo, si yo tenía cinco páginas de detalles de profundidad y me detuve para buscar rápidamente algo que, resultó, no existía, puedo volver a esas páginas de detalle Y seguir subiendo uno o más para seguir diferentes vínculos de detalle.)

Prueba esto..

  FragmentManager manager = getSupportFragmentManager(); if (manager.getBackStackEntryCount() > 0) getSupportFragmentManager().popBackStack(); else finish(); 
  • Android - android.view.InflateException: Archivo XML binario línea # 8: Error al inflar fragmento de clase
  • Cómo cambiar las pestañas programatically en android de fragmento?
  • Interfaces de actividad de Android para fragmentos: try / catch bloques vs. instancia de cheques
  • Permitir rotación / paisaje en un fragmento
  • Reemplazar un fragmento con otro en ViewPager
  • Android Studio obtener "Debe implementar OnFragmentInteractionListener"
  • Fragmento pila trasera no funciona cuando se extiende AppCompatActivity
  • Fragmentos superpuestos con DrawerLayout / NavigationView
  • Actualizar el fragmento ListView cuando no está enfocado
  • Crash al devolver el fragmento como una pestaña. Ver con la misma ID
  • Implementación de pestañas de barras de acción con fragmentos
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.