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

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

Я просто получил трассировку стека от «диких» жалоб, что я пытался совершить транзакцию фрагмента после вызова onSaveInstanceState. Но я делаю фиксацию в методе onResume! Почему андроид жалуется на это? У меня есть android: 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) 

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

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

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

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

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

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

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

    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(); } } 

    Обновление. Я думаю, что нашел объяснение и решение здесь: 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 и постоянно получаю это нелепое исключение от некоторых случайных пользователей. Я не могу воспроизвести его локально.

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

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

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

    То, что я сделал, следующее:

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