The layout of my Android tablet app consists of a list of items and a details view. When a list item is selected the associated content is displayed in the details view.
+--------+-------------+
| Item 1 | |
+--------+ Item |
| Item 2 | details |
+--------+ |
| Item 3 | |
+--------+-------------+
The details view is a Fragment
which is programmatically inflated into a FrameLayout
placeholder:
<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 instances [Dx]
of the DetailsFragment
are added to the backstack when the user selects one item after another.
[D3]
[D2] [D2]
[D1] -> [D1] -> [D1]
Therefore, the user needs to press the BACK button multiple times to pop the instances from the backstack to empty the details view.
How can I replace an existing instance [Dx]
of DetailsFragment
on the backstack when the fragmentTag
of the existing fragment
matches the fragmentTag
of a new fragment
?
[D1] -> [D2] -> [D3]
Since you want only one back stack entry per Fragment , make the back state name the Fragment's class name (via getClass(). getName() ). Then when replacing a Fragment , use the popBackStackImmediate() method. If it returns true, it means there is an instance of the Fragment in the back stack.
findFragmentById(R. id. fragment_container); Alternatively, you can assign a unique tag to a fragment and get a reference using findFragmentByTag() .
Fragment tags can be used to avoid recreating a Fragment on Activity orientation change.
I'm not sure I understand your question correctly. If you want to replace multiple fragments with some tag from the top of the backstack with a single fragment with the same tag then you can use the following approach.
Instead of using tags for identifying fragments set different backstack names for fragments of different types. You can still use a fragment tag but it will not help in solving this particular problem. Then remove fragments from the backstack manually one by one until there's a fragment with a different backstack name on the top or no fragments left.
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 backstack will contain just 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
You could use the tag and handle it in onBackPressed()
, but I think it would be a cleaner solution to handle it while constructing the back stack. Selectively add to the back stack for each FragmentTransaction, and only add to the back stack if it's the first instance of the DetailsFragment.
Here is a simple example that prevents any given Fragment from being added 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();
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With