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
- FragmentManager popBackStack no funciona - Bug?
- Android - SupportMapFragment con GoogleMaps API 2.0 dando IllegalArgumentException
- Eliminar Elemento + Desplazarse a Siguiente en Android ViewPager
- Ciclo de vida de Android Fragment sobre cambios de orientación
- Fragmento de diálogo en pantalla completa de Android
@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.)
- ClassCastException en una subclase de ListFragment utilizando la biblioteca de compatibilidad
- ¿Cómo puedo agregar filas a un listview de forma asíncrona?
- Fragmentos de Viewpager no se muestran después de la primera vez
- Unidad probar un fragmento de Android
- Comunicación entre un fragmento y una actividad - mejores prácticas
- Dos fragmentos en una página de viewpager
- Android actualiza una lista de fragmentos de su actividad principal
- Circular ViewPager que utiliza FragmentPagerAdapter
Prueba esto..
FragmentManager manager = getSupportFragmentManager(); if (manager.getBackStackEntryCount() > 0) getSupportFragmentManager().popBackStack(); else finish();
- ¿Es posible conectar el dispositivo Android Wear con otro dispositivo BLE directamente sin interacción del dispositivo telefónico?
- Com.android.support:design:23.3.0 roto cuando se usa la vista personalizada en Tablayout