How to merge fragments on backstack that match their fragment tag?

The layout of my Android tablet app consists of a list of items and a detailed view. When a list item is selected, the corresponding content is displayed in the detail view.

+--------+-------------+ | Item 1 | | +--------+ Item | | Item 2 | details | +--------+ | | Item 3 | | +--------+-------------+ 

The detail view is a Fragment that is programmatically inflated to the FrameLayout :

 <FrameLayout android:id="@+id/detail_fragment_placeholder" android:layout_width="match_parent" android:layout_height="match_parent"> 

Here is the Fragment operation:

 getSupportFragmentManager() .beginTransaction() .replace(containerViewId, fragment, fragmentTag) .addToBackStack(backStackStateName) .commit(); 

Multiple [Dx] instances of DetailsFragment are added to the stack when the user selects one item after another.

  [D3] [D2] [D2] [D1] -> [D1] -> [D1] 

Therefore, the user needs to press the BACK button several times to push the instances out of the back stack to clear the detail view.

How to replace an existing [Dx] instance with DetailsFragment with a backstack when the fragmentTag existing Fragment matches the fragmentTag new Fragment ?

 [D1] -> [D2] -> [D3] 
+5
source share
3 answers

I'm not sure I understand your question correctly. If you want to replace several fragments with a tag from the top of the backstack with one fragment with the same tag, you can use the following approach.

Instead of using tags to identify fragments, they set different backstack names for fragments of different types. You can still use the fragment tag, but that will not help in solving this particular problem. Then manually remove fragments from the stack one at a time until a fragment with a different backstack name appears at the top or without fragments.

  public void addFragment(final int containerViewId, final Fragment fragment, final String backStackName, final boolean replace) { final FragmentManager fragmentManager = getSupportFragmentManager(); if (replace) { while (fragmentManager.getBackStackEntryCount() > 0) { final int last = fragmentManager.getBackStackEntryCount() - 1; final FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(last); if (!TextUtils.equals(entry.getName(), backStackName)) { break; } fragmentManager.popBackStackImmediate(); } } fragmentManager .beginTransaction() .replace(containerViewId, fragment) .addToBackStack(backStackName) .commit(); fragmentManager.executePendingTransactions(); } 

Now, if you make the following calls, your backside will only contain fragment1 and fragment4 .

 addFragment(R.id.container, fragment1, "D2", false); addFragment(R.id.container, fragment2, "D1", false); addFragment(R.id.container, fragment3, "D1", false); addFragment(R.id.container, fragment4, "D1", true); 

UPDATE

In this particular case, the following code was enough:

 getSupportFragmentManager().popBackStack( backStackStateName, FragmentManager.POP_BACK_STACK_INCLUSIVE); getSupportFragmentManager() .beginTransaction() .replace(containerViewId, fragment, fragmentTag) .addToBackStack(backStackStateName) .commit(); 

https://github.com/tuxmobil/CampFahrplan/pull/148

+1
source

You can use the tag and process it in onBackPressed() , but I think that would be a cleaner solution to handle it when building the back stack. Selectively add to the back stack for each FragmentTransaction and add only to the back stack if this is the first instance of DetailFragment.

Here is a simple example that does not allow you to add any given fragment to the back stack twice in a row:

 public void replaceFragment(Fragment frag) { FragmentManager fm = getSupportFragmentManager(); if (fm != null){ FragmentTransaction t = fm.beginTransaction(); //you could also use containerViewId in place of R.id.detail_fragment_placeholder Fragment currentFrag = fm.findFragmentById(R.id.detail_fragment_placeholder); if (currentFrag != null && currentFrag.getClass().equals(frag.getClass())) { t.replace(R.id.detail_fragment_placeholder, frag).commit(); } else { t.replace(R.id.detail_fragment_placeholder, frag).addToBackStack(null).commit(); } } } 
+1
source

Just find the fragment on the back side and replace it:

 Fragment fragment = getSupportFragmentManager().findFragmentByTag("your tag"); FragmentTransaction transaction = fm.beginTransaction(); transaction.replace(R.id.fragment_container, fragment, fragment.getClass().getName()); transaction.addToBackStack("your tag"); transaction.commit(); 

And in your OnClick event, check to see if the position of the item matches the current item that is already displayed. If so, do nothing.

0
source

Source: https://habr.com/ru/post/1241271/


All Articles