OnResume snippets from the back stack

I am using a compatibility package to use snippets with Android 2.2. When you use fragments and add transitions between them in the backstack, I would like to achieve the same onResume behavior for activity, that is, whenever a fragment is brought to the fore (visible to the user) after exiting backstack, I would like some or callback was activated inside the fragment (for example, to make certain changes to a shared interface resource).

I saw that the built-in callback inside the framework is missing. is there any good practice to achieve this?

+83
android compatibility android-3.0-honeycomb android-fragments back-stack
Jun 28 2018-11-11T00:
source share
12 answers

Due to the lack of a better solution, I got this for me: Suppose I have 1 activity (MyActivity) and several fragments that replace each other (only one is visible at a time).

In MyActivity add this listener:

getSupportFragmentManager().addOnBackStackChangedListener(getListener()); 

(As you can see, I am using a compatibility package).

getListener implementation:

 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() will be called after clicking "Back". a few caveats:

  • It is assumed that you have added all transactions to backscack (using FragmentTransaction.addToBackStack() )
  • It will be activated on each stack to change (you can store other things on the back stack, such as animation), so you can get multiple calls for the same instance of the fragment.
+98
Jun 28 '11 at 10:30
source share

I slightly changed the proposed solution. For me, this works better:

 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; } 
+31
Sep 11 '13 at 23:06 on
source share

The following section of Android Developers describes the communication mechanism Creating event callbacks for activity . To quote a line:

A good way to do this is to define a callback interface inside the fragment and require its execution. When an action receives a callback through the interface, it can share information with other fragments in the layout.

Edit: The fragment has onStart(...) , which is called when the fragment is visible to the user. Similar to a onResume(...) with visibility and active start. They are attached to their work colleagues. In short: use onResume()

+4
Jun 28 2018-11-11T00:
source share

After popStackBack() you can use the following callback: onHiddenChanged(boolean hidden) inside your fragment

+3
Apr 16 '15 at 15:35
source share

If a snippet is placed in the backstack, Android simply destroys its presentation. The fragment instance itself is not killed. A simple way to start is to listen for the onViewCreated event, put the logic "onResume ()" there.

 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 } 
+2
Nov 01 '14 at 12:38 on
source share

Slightly improved and completed as a manager's decision.

Things to keep in mind. FragmentManager is not single, it only manages fragments inside the Activity, so in every action it will be new. In addition, this solution still does not take into account the ViewPager, which calls the setUserVisibleHint () method, which helps control the visibility of the fragments.

Feel free to use the following classes when dealing with this problem (uses Dagger2 injection). Call in action:

 //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 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); } 
+2
Sep 22 '15 at 9:17
source share

onResume () for the fragment works fine ...

 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); } ... 
+1
Oct. 14 '14 at 4:37
source share

In my activity onCreate ()

 getSupportFragmentManager().addOnBackStackChangedListener(getListener()); 

Use this method to catch a specific fragment and call 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; } 
+1
Mar 17 '16 at 11:42 on
source share

This is the correct answer that you can call onResume (), provided that the fragment is bound to activity. Alternatively you can use onAttach and onDetach

0
01 Oct
source share
 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(); } } 

and eventually your frament from rootfragment to see the effect

0
Mar 24 '16 at 8:34
source share

My workaround is to get the current name of the action bar in the Snippet before setting it to a new title. Thus, after the fragment appears, I can return to this header.

 @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(); } 
0
May 19 '16 at 7:41 a.m.
source share

I used enum FragmentTags to define all my fragment classes.

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

pass FragmentTags.TAG_FOR_FRAGMENT_A.name() as a fragment tag.

and now on

 @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; } 
0
Jan 20 '17 at 19:04 on
source share



All Articles