Fragmentos onResume de la stack trasera

Estoy usando el paquete de compatibilidad para usar Fragments con Android 2.2. Cuando uso fragmentos y agrego transiciones entre ellos a la backstack, me gustaría lograr el mismo comportamiento de onResume de una actividad, es decir, cada vez que un fragmento se pone en “primer plano” (visible para el usuario) después de salir del backstack, me gustaría que se active algún tipo de callback dentro del fragmento (para realizar ciertos cambios en un recurso de IU compartido, por ejemplo).

Vi que no hay una callback integrada dentro del marco de fragmentos. ¿Hay una buena práctica para lograr esto?

A falta de una solución mejor, conseguí que esto funcionara para mí: supongamos que tengo 1 actividad (MyActivity) y pocos fragmentos que se reemplacen (solo uno es visible a la vez).

En MyActivity, agregue este oyente:

 getSupportFragmentManager().addOnBackStackChangedListener(getListener()); 

(Como puede ver, estoy usando el paquete de compatibilidad).

Implementación de getListener:

 private OnBackStackChangedListener getListener() { OnBackStackChangedListener result = new OnBackStackChangedListener() { public void onBackStackChanged() { FragmentManager manager = getSupportFragmentManager(); if (manager != null) { MyFragment currFrag = (MyFragment) manager.findFragmentById(R.id.fragmentItem); currFrag.onFragmentResume(); } } }; return result; } 

MyFragment.onFragmentResume() después de presionar “Atrás”. algunas advertencias sin embargo:

  1. Supone que ha agregado todas las transacciones a la backstack (usando FragmentTransaction.addToBackStack() )
  2. Se activará con cada cambio de stack (puede almacenar otras cosas en la stack posterior, como la animación) para que pueda recibir varias llamadas para la misma instancia de fragmento.

Cambié la solución sugerida un poco. Funciona mejor para mí así:

 private OnBackStackChangedListener getListener() { OnBackStackChangedListener result = new OnBackStackChangedListener() { public void onBackStackChanged() { FragmentManager manager = getSupportFragmentManager(); if (manager != null) { int backStackEntryCount = manager.getBackStackEntryCount(); if (backStackEntryCount == 0) { finish(); } Fragment fragment = manager.getFragments() .get(backStackEntryCount - 1); fragment.onResume(); } } }; return result; } 

La siguiente sección de Desarrolladores de Android describe un mecanismo de comunicación Creación de devoluciones de llamadas de eventos a la actividad . Para citar una línea de ella:

Una buena forma de hacerlo es definir una interfaz de callback dentro del fragmento y exigir que la actividad del host la implemente. Cuando la actividad recibe una callback a través de la interfaz, puede compartir la información con otros fragmentos en el diseño según sea necesario.

Editar: El fragmento tiene un onStart(...) que se invoca cuando el fragmento es visible para el usuario. Del mismo modo un onResume(...) cuando es visible y se ejecuta activamente. Estos están vinculados a sus contrapartes de actividad. En resumen: use onResume()

Después de popStackBack() puede usar la siguiente callback: onHiddenChanged(boolean hidden) dentro de su fragmento

Si un fragmento se coloca en backstack, Android simplemente destruye su vista. La instancia del fragmento en sí no es eliminada. Una forma simple de comenzar debería ser escuchar el evento onViewCreated, y poner allí la lógica “onResume ()”.

 boolean fragmentAlreadyLoaded = false; @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { // TODO Auto-generated method stub super.onViewCreated(view, savedInstanceState); if (savedInstanceState == null && !fragmentAlreadyLoaded) { fragmentAlreadyLoaded = true; // Code placed here will be executed once } //Code placed here will be executed even when the fragment comes from backstack } 

Un poco mejorado y envuelto en una solución de administrador.

Cosas a tener en cuenta. FragmentManager no es un singleton, administra solo los Fragmentos dentro de la Actividad, por lo que en cada actividad será nueva. Además, esta solución hasta ahora no tiene en cuenta a ViewPager que llama al método setUserVisibleHint () que ayuda a controlar la visibilidad de los Fragmentos.

Siéntase libre de usar las siguientes clases cuando se trata de este problema (utiliza la inyección de Dagger2). Actividad de llamada en:

 //inject FragmentBackstackStateManager instance to myFragmentBackstackStateManager FragmentManager fragmentManager = getSupportFragmentManager(); myFragmentBackstackStateManager.apply(fragmentManager); 

FragmentBackstackStateManager.java:

 @Singleton public class FragmentBackstackStateManager { private FragmentManager fragmentManager; @Inject public FragmentBackstackStateManager() { } private BackstackCallback backstackCallbackImpl = new BackstackCallback() { @Override public void onFragmentPushed(Fragment parentFragment) { parentFragment.onPause(); } @Override public void onFragmentPopped(Fragment parentFragment) { parentFragment.onResume(); } }; public FragmentBackstackChangeListenerImpl getListener() { return new FragmentBackstackChangeListenerImpl(fragmentManager, backstackCallbackImpl); } public void apply(FragmentManager fragmentManager) { this.fragmentManager = fragmentManager; fragmentManager.addOnBackStackChangedListener(getListener()); } } 

FragmentBackstackChangeListenerImpl.java:

 public class FragmentBackstackChangeListenerImpl implements FragmentManager.OnBackStackChangedListener { private int lastBackStackEntryCount = 0; private final FragmentManager fragmentManager; private final BackstackCallback backstackChangeListener; public FragmentBackstackChangeListenerImpl(FragmentManager fragmentManager, BackstackCallback backstackChangeListener) { this.fragmentManager = fragmentManager; this.backstackChangeListener = backstackChangeListener; lastBackStackEntryCount = fragmentManager.getBackStackEntryCount(); } private boolean wasPushed(int backStackEntryCount) { return lastBackStackEntryCount < backStackEntryCount; } private boolean wasPopped(int backStackEntryCount) { return lastBackStackEntryCount > backStackEntryCount; } private boolean haveFragments() { List fragmentList = fragmentManager.getFragments(); return fragmentList != null && !fragmentList.isEmpty(); } /** * If we push a fragment to backstack then parent would be the one before => size - 2 * If we pop a fragment from backstack logically it should be the last fragment in the list, but in Android popping a fragment just makes list entry null keeping list size intact, thus it's also size - 2 * * @return fragment that is parent to the one that is pushed to or popped from back stack */ private Fragment getParentFragment() { List fragmentList = fragmentManager.getFragments(); return fragmentList.get(Math.max(0, fragmentList.size() - 2)); } @Override public void onBackStackChanged() { int currentBackStackEntryCount = fragmentManager.getBackStackEntryCount(); if (haveFragments()) { Fragment parentFragment = getParentFragment(); //will be null if was just popped and was last in the stack if (parentFragment != null) { if (wasPushed(currentBackStackEntryCount)) { backstackChangeListener.onFragmentPushed(parentFragment); } else if (wasPopped(currentBackStackEntryCount)) { backstackChangeListener.onFragmentPopped(parentFragment); } } } lastBackStackEntryCount = currentBackStackEntryCount; } } 

BackstackCallback.java:

 public interface BackstackCallback { void onFragmentPushed(Fragment parentFragment); void onFragmentPopped(Fragment parentFragment); } 

En mi actividad onCreate ()

 getSupportFragmentManager().addOnBackStackChangedListener(getListener()); 

Utilice este método para atrapar un Fragmento específico y invocar onResume ()

 private FragmentManager.OnBackStackChangedListener getListener() { FragmentManager.OnBackStackChangedListener result = new FragmentManager.OnBackStackChangedListener() { public void onBackStackChanged() { Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container); if (currentFragment instanceof YOURFRAGMENT) { currentFragment.onResume(); } } }; return result; } 

Esta es la respuesta correcta a la que puede llamar onResume () siempre que el fragmento esté adjunto a la actividad. Alternativamente, puede usar onAttach y onDetach

onResume () para el fragmento funciona bien …

 public class listBook extends Fragment { private String listbook_last_subtitle; ... @Override public void onCreate(Bundle savedInstanceState) { String thisFragSubtitle = (String) getActivity().getActionBar().getSubtitle(); listbook_last_subtitle = thisFragSubtitle; } ... @Override public void onResume(){ super.onResume(); getActivity().getActionBar().setSubtitle(listbook_last_subtitle); } ... 
 public abstract class RootFragment extends Fragment implements OnBackPressListener { @Override public boolean onBackPressed() { return new BackPressImpl(this).onBackPressed(); } public abstract void OnRefreshUI(); } public class BackPressImpl implements OnBackPressListener { private Fragment parentFragment; public BackPressImpl(Fragment parentFragment) { this.parentFragment = parentFragment; } @Override public boolean onBackPressed() { ((RootFragment) parentFragment).OnRefreshUI(); } } 

y, en última instancia, su Frament from RootFragment para ver el efecto

Mi solución es obtener el título actual de la barra de acciones en el Fragmento antes de establecerlo en el nuevo título. De esta forma, una vez que el Fragmento aparece, puedo volver a ese título.

 @Override public void onResume() { super.onResume(); // Get/Backup current title mTitle = ((ActionBarActivity) getActivity()).getSupportActionBar() .getTitle(); // Set new title ((ActionBarActivity) getActivity()).getSupportActionBar() .setTitle(R.string.this_fragment_title); } @Override public void onDestroy() { // Set title back ((ActionBarActivity) getActivity()).getSupportActionBar() .setTitle(mTitle); super.onDestroy(); } 

He usado enum FragmentTags para definir todas mis clases de fragmentos.

 TAG_FOR_FRAGMENT_A(A.class), TAG_FOR_FRAGMENT_B(B.class), TAG_FOR_FRAGMENT_C(C.class) 

pase FragmentTags.TAG_FOR_FRAGMENT_A.name() como etiqueta de fragmento.

y ahora

 @Override public void onBackPressed(){ FragmentManager fragmentManager = getFragmentManager(); Fragment current = fragmentManager.findFragmentById(R.id.fragment_container); FragmentTags fragmentTag = FragmentTags.valueOf(current.getTag()); switch(fragmentTag){ case TAG_FOR_FRAGMENT_A: finish(); break; case TAG_FOR_FRAGMENT_B: fragmentManager.popBackStack(); break; case default: break; }