IllegalStateException при добавлении фрагмента из Backstack - PullRequest
1 голос
/ 10 июля 2019

Время от времени я получаю следующий отчет о сбое:

java.lang.IllegalStateException: 
  at androidx.fragment.app.FragmentManagerImpl.addFragment (FragmentManagerImpl.java:1916)
  at androidx.fragment.app.BackStackRecord.executePopOps (BackStackRecord.java:828)
  at androidx.fragment.app.FragmentManagerImpl.executeOps (FragmentManagerImpl.java:2622)
  at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether (FragmentManagerImpl.java:2411)
  at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute (FragmentManagerImpl.java:2366)
  at androidx.fragment.app.FragmentManagerImpl.execPendingActions (FragmentManagerImpl.java:2273)
  at androidx.fragment.app.FragmentManagerImpl$1.run (FragmentManagerImpl.java:733)
  at android.os.Handler.handleCallback (Handler.java:808)
  at android.os.Handler.dispatchMessage (Handler.java:101)
  at android.os.Looper.loop (Looper.java:166)
  at android.app.ActivityThread.main (ActivityThread.java:7529)
  at java.lang.reflect.Method.invoke (Method.java)
  at com.android.internal.os.Zygote$MethodAndArgsCaller.run (Zygote.java:245)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:921)

В строке 1916 FragmentManagerImpl я могу найти:

throw new IllegalStateException("Fragment already added: " + fragment);

Таким образом, он говорит, что какой-то фрагмент уже добавлен,К сожалению, Google больше не показывает сообщение (какой фрагмент уже был добавлен) в консоли Google Play.Насколько я понимаю, Stacktrace это исключение возникает при добавлении фрагмента из backstack, верно?

У меня есть один FrameLayout, в который я добавляю / удаляю фрагменты.Я всегда добавляю их со следующим кодом:

public void addFragment(FragmentActivity activity, Fragment fragment) {
    FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
    String tag = fragment.getClass().getCanonicalName();
    Fragment prev = activity.getSupportFragmentManager().findFragmentByTag(tag);
    if (fragment.isAdded()) {
        return;
    }
    if (prev != null) {
        transaction.remove(prev);
    }
    transaction.replace(R.id.fragment_container, fragment, tag);
    transaction.addToBackStack(null);
    transaction.commit();

И добавляю DialogFragments следующим методом:

public void openFragmentDialog(FragmentActivity activity, DialogFragment dialogFragment, String tag) {
    FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
    Fragment prev = activity.getSupportFragmentManager().findFragmentByTag(tag);
    if (prev != null) {
        transaction.remove(prev);
    }
    transaction.addToBackStack(null);
    dialogFragment.show(transaction, tag);
}

В какой ситуации может произойти исключение IllegalStateException?Я добавляю / заменяю Fragments / DialogFragments неправильным способом?Я никогда не мог воспроизвести эту ошибку.Но я получаю отчеты от Android 4.4 - Android 9 и всех типов устройств, и я не знаю, где это может произойти.

Может ли это быть что-то с анимацией или медленными устройствами?Потому что это случается только изредка.

Ответы [ 3 ]

1 голос
/ 13 июля 2019

Обратите внимание, что вы добавляете и удаляете два разных фрагмента с одним и тем же тегом - тег также должен быть разным.Если фрагмент prev является экземпляром другого класса, почему вы используете имя класса fragment в качестве тега для его поиска?

Вы должны добавить оператор if, чтобы проверить, является ли prev и fragment иногда не совпадают (из-за одного и того же тега).

Если два фрагмента - это один и тот же экземпляр, и вы все еще хотите удалить, а затем добавить один и тот же фрагмент - вам может потребоваться сделать это в двух разных транзакциях, чтобы исключить исключение "Fragment already added".

1 голос
/ 12 июля 2019

tag должны быть уникальными. Если возможно, замените его на null, в противном случае на что-то уникальное.

public void addFragment(FragmentActivity activity, Fragment fragment) {
    FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.fragment_container, fragment);
    transaction.addToBackStack(null);
    transaction.commit();
}
0 голосов
/ 18 июля 2019

Вот что я сделал для проверки и предотвращения дублирования фрагментов:

MyFragment myFragment = (MyFragment) fragmentManager.findFragmentByTag(MY_FRAGMENT_TAG);

if(myFragment != null && myFragment.isVisible()){
    // Return early if the fragment already exists & is visible
    return;

}else if(myFragment == null){
    // Create a new instance of the fragment if none already exist
    myFragment = new MyFragment();
}

// Perform the fragment transaction
fragmentManager.beginTransaction()
    .replace(R.id.content_container, myFragment, MY_FRAGMENT_TAG)
    .addToBackStack(MY_FRAGMENT_TAG) // Pass in the tag if you want to add to the back stack
    .commit();

Для фрагментов диалога я просто создаю новый экземпляр и вызываю .show() для него.Диалог должен быть закрыт через взаимодействие с ним:

MyDialog myDialog = new MyDialog();

// I call getChildFragmentManager here b/c I was using this from within a fragment
// but you can get whichever Fragment Manager is appropriate
myDialog.show(getChildFragmentManager(), MY_DIALOG_TAG);
...