"Невозможно выполнить это действие после onSaveInstanceState" - почему я получаю это исключение из своего метода onResume?

Моя активность вызывает камеру с намерением ACTION_IMAGE_CAPTURE. Если активность камеры возвращается успешно, я устанавливаю флаг в обратном вызове onActivityResult и на основании значения флага запускаю фрагмент в моем onResume, чтобы добавить заголовок к захваченному изображению. Кажется, это работает нормально.

Я только что получил трассировку стека от "диких" жалоб, что я пытался совершить транзакцию фрагмента после вызова onSaveInstanceState. Но я делаю фиксацию в методе onResume! Почему андроид жалуется на это? У меня есть андроид: configChanges = "orientation | keyboardHidden | keyboard | screenSize" , установленный в моем AndroidManifest.xml, поэтому изменение ориентации не должно запускать это....

Это произошло на Samsung Galaxy S3 (SGH-i747) с 4.0.4

Вот стек:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
    at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1314)
    at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1325)
    at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:548)
    at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:532)
    at com.Familiar.Android.FamiliarAppV1.AddPhotosActivity2.performFragmentTransition(AddPhotosActivity2.java:278)
    at com.Familiar.Android.FamiliarAppV1.AddPhotosActivity2.switchToCaptionsFragment(AddPhotosActivity2.java:438)
    at com.Familiar.Android.FamiliarAppV1.AddPhotosActivity2.onResume(AddPhotosActivity2.java:167)
    at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1158)
    at android.app.Activity.performResume(Activity.java:4544)
    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2448)
    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2486)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1187)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4514)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:980)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:747)
    at dalvik.system.NativeStart.main(Native Method)

Любая помощь или мудрость оценены.

Ответ 1

Я думаю. Я знаю ответ. Я использую библиотеку совместимости FragmentActivity из v4, поэтому мне нужно выполнить транзакции фрагментов в onResumeFragments, а не в onResume. Может кто-нибудь подтвердить?

Ответ 2

вы можете использовать метод commitAllowingStateLoss()

но помните, что вы можете потерять состояние своей деятельности как вы можете видеть в справочной системе google android reference которые объясняют разные между ними следующим образом:

Подобно commit(), но позволяет выполнить фиксацию после сохранения состояния активности. Это опасно, потому что фиксация может быть потеряна, если действие необходимо восстановить позже из состояния, поэтому это должно использоваться только в тех случаях, когда пользовательское пользовательское состояние нормально изменяется на пользователя.

из моего опыта это может привести к тому, что метод addToBackStack не будет работать иногда, поэтому вам нужно будет добавить его вручную на фрагмент и, конечно, состояние не будет сохранено (текстовый текст ext.)

Ответ 3

это сработало для меня... нашло это самостоятельно... надеюсь, это поможет вам!

1) НЕ имеют глобального "статического" FragmentManager/FragmentTransaction.

2) onCreate, ВСЕГДА снова инициализируем FragmentManager!

образец ниже: -

public abstract class FragmentController extends AnotherActivity{
protected FragmentManager fragmentManager;
protected FragmentTransaction fragmentTransaction;
protected Bundle mSavedInstanceState;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mSavedInstanceState = savedInstanceState;
    setDefaultFragments();
}

protected void setDefaultFragments() {
    fragmentManager = getSupportFragmentManager();
    //check if on orientation change.. do not re-add fragments!
    if(mSavedInstanceState == null) {
        //instantiate the fragment manager

        fragmentTransaction = fragmentManager.beginTransaction();

        //the navigation fragments
        NavigationFragment navFrag = new NavigationFragment();
        ToolbarFragment toolFrag = new ToolbarFragment();

        fragmentTransaction.add(R.id.NavLayout, navFrag, "NavFrag");
        fragmentTransaction.add(R.id.ToolbarLayout, toolFrag, "ToolFrag");
        fragmentTransaction.commitAllowingStateLoss();

        //add own fragment to the nav (abstract method)
        setOwnFragment();
    }
}

Ответ 4

Обновить Я думаю, что нашел объяснение и решение здесь: http://code.google.com/p/android/issues/detail?id=23096#c4 Я реализовал "Обходное решение для фрагментов", размещенное там, и до сих пор не получил больше исключения IllegalStateException.

Я добавляю фрагмент невидимого состояния в свою деятельность следующим образом:

@Override
protected void onCreate(final Bundle args) {
    ...
    if (args == null) {
        final FragmentManager fm = this.getSupportFragmentManager();
        final FragmentTransaction ft = fm.beginTransaction();
        final Fragment emptyFragmentWithCallback = new EmptyFragmentWithCallbackOnResume();
        ft.add(emptyFragmentWithCallback, EmptyFragmentWithCallbackOnResume.TAG);
        ft.commit();
    }

Следующий код берется из ссылки выше:

public class EmptyFragmentWithCallbackOnResume extends Fragment {
OnFragmentAttachedListener mListener = null;

@Override
public void onAttach(SupportActivity activity) {
    super.onAttach(activity);
    try {
        mListener = (OnFragmentAttachedListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString() + " must implement OnFragmentAttachedListener");
    }
}

@Override
public void onResume() {
    super.onResume();
    if (mListener != null) {
        mListener.OnFragmentAttached();
    }
}

public interface OnFragmentAttachedListener {
    public void OnFragmentAttached();
}
}

и вызвать транзакции фрагментов, которые интуитивно перейдут в onResume или onResumeFragments в мой собственный onFragmentAttached метод, который вызывается невидимым фрагментом состояния. Я вообще не использую onResumeFragments и не делаю никаких транзакций фрагментов в onResume.

Итак, подведем итог. Если вы используете библиотеку поддержки и фрагменты, почти забывайте о onResume, забудьте о onResumeFragments и реализуйте свой собственный onResume на основе вышеописанного решения. Это несколько смешно.


Я не могу подтвердить. У меня точно такая же проблема. хотя я делаю транзакцию фрагментов в onResumeFragments. Это работало так, как я писал здесь: IllegalStateException - библиотека поддержки фрагментов.

Похоже, что ошибка возникает только в 4.0.3 и 4.0.4. Однако это не происходит ни всегда, ни в моем эмуляторе.

Я использую поддержку lib rev. 10 и API 16. Я вызываю DialogFragment.show в onResumeFragments и постоянно получаю это нелепое исключение от некоторых случайных пользователей. Я не могу воспроизвести его локально.

Ответ 5

Сначала я разработал приложение для Android Android 2.2 (SDK 8), используя библиотеку поддержки v4, и когда я начал использовать его с 4.2 (SDK 17), у меня были те же проблемы с моими фрагментами. Но изменение моего манифеста на андроид: minSdkVersion = "8" android: targetSdkVersion = "17", решил мои проблемы. Может быть, это и вас тоже.

Ответ 6

Я всегда получал это, когда пытался показать фрагмент в методе onActivityForResult(), поэтому проблема следующая:

  • Моя активность приостановлена ​​и остановлена, что означает, что onSaveInstanceState() уже был вызван (для устройств с предварительной сотой и после сотовой связи).
  • В случае любого результата я сделал транзакцию, чтобы показать/скрыть фрагмент, что вызывает это исключение IllegalStateException.

Что я сделал дальше:

  • Добавлена ​​ценность для определения того, было ли выполнено действие, которое я хочу (например, взятие фотографии из camere - isPhotoTaken) - это может быть логическое или целочисленное значение, зависящее от того, сколько разных транзакций вам нужно.
  • В overriden onResumeFragments() метод я проверил на свое значение и после сделанных транзакций фрагментов, которые мне нужны. В этом случае commit() не был выполнен после onSaveInstanceState, поскольку состояние было возвращено в методе onResumeFragments().

Ответ 7

**Add this to your Activity:-**

 @Override
    protected void onSaveInstanceState(Bundle outState) {
        //No call for super(). Bug on API Level > 11.
    }