android - Fragmentos onResume de la pila trasera
android-fragments compatibility (12)
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:
- Supone que ha agregado todas las transacciones a la backstack (usando
FragmentTransaction.addToBackStack()
) - Se activará con cada cambio de pila (puede almacenar otras cosas en la pila posterior, como la animación) para que pueda recibir varias llamadas para la misma instancia de fragmento.
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 devolución de llamada dentro del fragmento (para realizar ciertos cambios en un recurso de IU compartido, por ejemplo).
Vi que no hay una devolución de llamada integrada dentro del marco de fragmentos. ¿Hay una buena práctica para lograr esto?
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;
}
Después de popStackBack()
puede usar la siguiente devolución de llamada: onHiddenChanged(boolean hidden)
dentro de su fragmento
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
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;
}
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 devolución de llamada dentro del fragmento y exigir que la actividad del host la implemente. Cuando la actividad recibe una devolución de llamada 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()
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();
}
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<Fragment> 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<Fragment> 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);
}
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