Ответ 1
Я думаю. Я знаю ответ. Я использую библиотеку совместимости FragmentActivity из v4, поэтому мне нужно выполнить транзакции фрагментов в onResumeFragments, а не в 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)
Любая помощь или мудрость оценены.
Я думаю. Я знаю ответ. Я использую библиотеку совместимости FragmentActivity из v4, поэтому мне нужно выполнить транзакции фрагментов в onResumeFragments, а не в onResume. Может кто-нибудь подтвердить?
вы можете использовать метод commitAllowingStateLoss()
но помните, что вы можете потерять состояние своей деятельности как вы можете видеть в справочной системе google android reference которые объясняют разные между ними следующим образом:
Подобно commit(), но позволяет выполнить фиксацию после сохранения состояния активности. Это опасно, потому что фиксация может быть потеряна, если действие необходимо восстановить позже из состояния, поэтому это должно использоваться только в тех случаях, когда пользовательское пользовательское состояние нормально изменяется на пользователя.
из моего опыта это может привести к тому, что метод 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(), поэтому проблема следующая:
Что я сделал дальше:
**Add this to your Activity:-**
@Override
protected void onSaveInstanceState(Bundle outState) {
//No call for super(). Bug on API Level > 11.
}