0

In my sample, I try to learn the difference between commitAllowingStateLoss() and commit() methods for fragments. Now I know IllegalArgumentException will appear if using commit() after activity save instance (for example, executed commit() when activity was in background).

But another problem appears, fragments overlap. I don't know why, and cannot solve the problem.

My code is as below.

In FragmentMainActivity there are two buttons for switching fragments.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <Button
        android:id="@+id/btn_fragment1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="fragment 1" />

    <Button
        android:id="@+id/btn_fragment2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="fragment 2" />
</LinearLayout>

<FrameLayout
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffffff"></FrameLayout>

The framelayout with id "root" is the container for fragments.

public class FragmentMainActivity extends AppCompatActivity implements View.OnClickListener {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_fragment_main);

    findViewById(R.id.btn_fragment1).setOnClickListener(this);
    findViewById(R.id.btn_fragment2).setOnClickListener(this);
}

PlusOneFragment plusOneFragment;
PlusTwoFragment plusTwoFragment;

@Override
public void onClick(View v) {
    int i = v.getId();
    if (i == R.id.btn_fragment1) {
        findViewById(R.id.root).postDelayed(new Runnable() {
            @Override
            public void run() {
                final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                if (getSupportFragmentManager().findFragmentByTag("tag1") == null) {
                    plusOneFragment = PlusOneFragment.newInstance("1", "2");
                    transaction.add(R.id.root, plusOneFragment, "tag1");
                } else {
                    plusOneFragment = (PlusOneFragment) getSupportFragmentManager().findFragmentByTag("tag1");
                }
                if (getSupportFragmentManager().findFragmentByTag("tag2") != null) {
                    plusTwoFragment = (PlusTwoFragment) getSupportFragmentManager().findFragmentByTag("tag2");
                    transaction.hide(plusTwoFragment);
                }
                transaction.show(plusOneFragment).commitAllowingStateLoss();
            }
        }, 3000);
    } else if (i == R.id.btn_fragment2) {
        findViewById(R.id.root).postDelayed(new Runnable() {
            @Override
            public void run() {
                final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                if (getSupportFragmentManager().findFragmentByTag("tag2") == null) {
                    plusTwoFragment = PlusTwoFragment.newInstance("1", "2");
                    transaction.add(R.id.root, plusTwoFragment, "tag2");
                } else {
                    plusTwoFragment = (PlusTwoFragment) getSupportFragmentManager().findFragmentByTag("tag2");
                }
                if (getSupportFragmentManager().findFragmentByTag("tag1") != null) {
                    plusOneFragment = (PlusOneFragment) getSupportFragmentManager().findFragmentByTag("tag1");
                    transaction.hide(plusOneFragment);
                }
                transaction.show(plusTwoFragment).commitAllowingStateLoss();
            }
        }, 3000);
    }
}
}

First I click button1 to show fragment1, then click button2 to show fragment2, it works fine. After those operations, I click button1 again, and then click home, so the app is running in background. To simulated low memorey scene, I then kill the process. All those operations happened in 3s.

Finally, I opened the app from the recent records (activity recreated), found that the two fragments overlapped with each other. How does this happen?(why the problem not happened when the process is foreground?) And what can I do with this problem?

overlapping fragments

Jone
  • 13
  • 4
  • Give your fragments a background color (say white) and check again.Your fragments are not removed.Also try remove methods instead of add.Let me know if it helps – Anirudh Sharma Jun 14 '16 at 06:16
  • I'm adding this as an answer.Please accept. – Anirudh Sharma Jun 14 '16 at 06:39
  • Yes, add backgroud color will help. But I don't know why this happens. If the process is not killed, it works well without the background color. – Jone Jun 14 '16 at 06:42

2 Answers2

1

Give your fragments root element a background color (say white) android:background="@android:color/white" and check again. This is beacuse your fragments are not removed and added one over another.Also try replace methods instead of add.For ex:-

fragmentTransaction.replace("containerId", fragment);

as this replaces the previous fragment in layout.You can manually remove your fragment as well using

Fragment fragment = getSupportFragmentManager().findFragmentByTag(TAG_FRAGMENT);
if(fragment != null)
    getSupportFragmentManager().beginTransaction().remove(fragment).commit();
Anirudh Sharma
  • 7,968
  • 13
  • 40
  • 42
  • yes, both the methods works well. Would you explain why the problem not happened when the process is foreground? thanks. – Jone Jun 14 '16 at 06:52
  • @Jone This may be because your activity is recreated and your fragments and b are not destroyed and resume from their previous state instead of new state.Please check http://stackoverflow.com/questions/18590582/overlapping-fragments-when-resuming-activity and http://stackoverflow.com/questions/15074320/fragment-overlaps-on-activity-rotation – Anirudh Sharma Jun 14 '16 at 07:25
0

As fragment remains in backstack you have to remove first fragment from backstack when second is opening. Using popBackStack may resolve your problem

   Fragment fragment = (Fragment) YourClass.newInstance();

    FragmentManager fragmentManager = getSupportFragmentManager();
                    fragmentManager.popBackStack();
                    FragmentTransaction fragmentTransaction =   fragmentManager.beginTransaction();

                    fragmentTransaction.replace(R.id.flContent, fragment);
                    //TODO Add to backstack


                    fragmentTransaction.addToBackStack(null);

                    fragmentTransaction.commit();

I hope this may help you

Reena
  • 1,368
  • 1
  • 11
  • 25
  • yes, this helps. thanks. But replace() method will make the fragment destroyed. So I need use show() and hide() methods here. – Jone Jun 14 '16 at 06:55