Совершить уже вызванную ошибку при изменении фрагмента

Недавно я столкнулся с ошибкой «Невозможно выполнить это действие после onSaveInstanceState» при предоставлении разрешения (Android M) на доступ к внешнему хранилищу. Я занялся и решил проблему в соответствии с этой записью (как я думал).

Теперь я столкнулся с новой проблемой, поскольку я получаю сообщение об ошибке "фиксация уже вызвана" при попытке изменить фрагмент.

Как только я хочу переключиться на определенный фрагмент (например, дискуссионный фрагмент), я получаю сообщение об ошибке «фиксация уже вызвана», см. logcat.

Я уже искал некоторые решения в stackoverflow, но, кажется, не вижу, что не так, я знаю, что есть много коммитов, но как справиться с этим в моей ситуации? Кто-нибудь может мне помочь?

Звоните в Обсуждениефрагмент:

public class DiscussionsActivity extends BaseActivity
{
..
  discussionsFragment = DiscussionsFragment.getInstance(id);
  changeContent(discussionsFragment, R.id.content, false); <---
..
}

Базовая активность:

public class BaseActivity extends AppCompatActivity {

    protected Fragment currentFragment;
    protected MainFragment mainFragment;
    private FragmentManager fragmentManager;
    private FragmentTransaction transaction;
    private boolean mReturningWithResult = false;

    public void changeContent(Fragment fragment, int content, boolean inBackStack) {
        InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
        try {
            inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
        } catch (Exception e) {
        }
        fragmentManager = getSupportFragmentManager();
        String newTag = ((Object) fragment).getClass().getName() + ":" + fragmentManager.getBackStackEntryCount();

        transaction = fragmentManager.beginTransaction().replace(content, fragment, newTag);

        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        if (inBackStack) {
            transaction.addToBackStack(fragment.getClass().getSimpleName());
        } else
            mReturningWithResult = true; <--- handle onSaveInstanceState error in onResume
            try {
                fragmentManager.popBackStackImmediate();
                transaction.commit();
            } catch (IllegalStateException ignored) {
                // There's no way to avoid getting this if saveInstanceState has already been called.
            }

        currentFragment = fragment;
    }

@Override
    public void onResume() {
        super.onResume();
        if (mReturningWithResult) {
            fragmentManager.popBackStackImmediate();

            if (currentFragment != mainFragment) {
                transaction.commit(); <---- HERE THE CRASH HAPPENS
            }
        }
        // Reset the boolean flag back to false for next time.
        mReturningWithResult = false;
    }

Логкат:

FATAL EXCEPTION: main
Process: some.com.app, PID: 17374
java.lang.RuntimeException: Unable to resume activity {some.com.app/some.com.app.UI.Discussion.DiscussionsActivity_}: java.lang.IllegalStateException: commit already called
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3103)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3134)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2481)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.IllegalStateException: commit already called
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:683)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:662)
at some.com.app.UI.Base.BaseActivity.onResume(BaseActivity.java:144) <--

person Simon    schedule 14.12.2016    source источник
comment
Вам нужно начинать новую FragmentTransaction каждый раз, когда вы собираетесь выполнить любое количество операций Fragment.   -  person Nas    schedule 14.12.2016
comment
Но это то, что я делаю в changeContent? Не могли бы вы привести пример в соответствии с моим кодом, каким он должен быть?   -  person Simon    schedule 14.12.2016


Ответы (2)


удалить глобальную транзакцию FragmentTransaction и объявить ее локально

public void changeContent(Fragment fragment, int content, boolean inBackStack) {
        InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
        try {
            inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
        } catch (Exception e) {
        }
        fragmentManager = getSupportFragmentManager();
        String newTag = ((Object) fragment).getClass().getName() + ":" + fragmentManager.getBackStackEntryCount();

        FragmentTransaction  transaction = fragmentManager.beginTransaction().replace(content, fragment, newTag);

        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        if (inBackStack) {
            transaction.addToBackStack(fragment.getClass().getSimpleName());
        } else
            mReturningWithResult = true; <--- handle onSaveInstanceState error in onResume
            try {
                transaction.commit();
            } catch (IllegalStateException ignored) {
                // There's no way to avoid getting this if saveInstanceState has already been called.
            }

        currentFragment = fragment;
    }
person Nas    schedule 14.12.2016
comment
Спасибо, Nas, но проблема заключается в onResume, что там происходит? Так как сейчас MainActivity вообще не показывает. - person Simon; 14.12.2016

Вы можете попытаться выполнить фиксацию дважды с одной и той же транзакцией фрагмента после оператора фиксации. Создайте новую транзакцию фрагмента, если предыдущая транзакция уже зафиксирована.

Также рекомендуем для обеспечения commit() использования точки отладки.

public void changeContent(Fragment fragment, int content, boolean inBackStack) {
 ...........
 ...........
     try {
         fragmentManager.popBackStackImmediate();
         transaction.commit();
       } catch (IllegalStateException ignored) {
       // There's no way to avoid getting this if saveInstanceState has already been called.

 ...........
 ...........


      }


@Override
 public void onResume() {
     super.onResume();
      ...........
      ...........
       //This method would be called at second time.

       transaction.commit(); <---- HERE THE CRASH HAPPENS

        // Reset the boolean flag back to false for next time.
        mReturningWithResult = false;
      ...........
      ...........
    }
person QuokMoon    schedule 14.12.2016