Prevent The Same Fragment From Stacking More Than

2020-03-02 03:01发布

I have an Activity with three Fragments lets call them A, B and C. Fragment A is called in the Activity onCreate().

FragmentA fragA = new FragmentA();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.activity2_layout, fragA, "A");
transaction.commit();

And gets replaced with Fragment B or C when certain buttons are pressed, and the FragmentTransaction calls addToBackStack().

FragmentB fragB = new FragmentB(); //or C
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.activity2_layout, fragB, "B");  //or C
transaction.addToBackStack("B"); //or C
transaction.commit();

But lets say I call Fragment B three times in a row, how can I prevent it from stacking on to it self? And at the same time I want this to be possible: B called > C called > B called - BUT when i try to go back I want B to be opened only once ( C < B) instead of (B < C < B). So basically removing the first backStack with the new one.

2条回答
2楼-- · 2020-03-02 03:50

I have solved one of your questions, namely how can I prevent it from stacking on to it self?, in one of my own projects a while ago. This was the exact code I used there:

public void setContent(@NonNull Fragment fragment, boolean addToBackStack) {
    Fragment current = getSupportFragmentManager().findFragmentById(R.id.main_content);
    if (current == null || !current.getClass().equals(fragment.getClass())) {
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        if (addToBackStack) {
            transaction.addToBackStack(null).add(R.id.main_content, fragment).commit();
        } else {
            transaction.replace(R.id.main_content, fragment).commit();
        }
    }
}

What this code does is checks of what class the currently showing Fragment is and compare that to the fragment you want to replace it with. If they are the same, it doesn't do anything. This code can be shaped to fit your needs like so

Fragment newFragment = new FragmentB(); //OR FragmentC
Fragment current = getSupportFragmentManager().findFragmentById(R.id.activity2_layout);
if (!current.getClass().equals(newFragment.getClass())) {

    //POP BACKSTACK HERE LIKE EXPLAINED BELOW

    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    final String tag = newFragment.getClass().getSimpleName();
    transaction.addToBackStack(tag);
    transaction.add(R.id.activity2_layout, newFragment, tag);
    transaction.commit();
} else {
    //THROW AN ERROR OR SOMETHING, HANDLE IT BEING THE SAME
}

Making sure that only one fragment of a certain type is present at a time could probably be achieved by popping the backstack until before the first occurence of the same fragment. I have not written any code for this but it shouldn't be too difficult to implement that feature. If you can't figure it out yourself, let me know and I will try to write you an example :)

查看更多
对你真心纯属浪费
3楼-- · 2020-03-02 03:51

From How to resume Fragment from BackStack if exists, which maybe very similar to your query.

There is a way to pop the back stack based on either the transaction name or the id provided by commit (for eg. using the Fragment's class name as Thijs already mentioned):

String backStateName = fragment.getClass().getName();

Adding to backstack:

FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(backStateName);
ft.commit();

When popping:

getSupportFragmentManager().popBackStackImmediate (backStateName, 0); 

So before replacing fragment, we can check existance in backstack like:

boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);

if (!fragmentPopped){ //fragment not in back stack, create it.
    ...
    ...
    ft.addToBackStack(backStateName);
    ft.commit();
}

Please check the above question and the accepted answer for more explanation.

查看更多
登录 后发表回答