java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

1. 场景:

  在开发过程中遇到这么一个需要,在主页点击按钮进入另一个Activity(ReadActivity),在该ReadActivity中点击一个按钮再返回主页并指定主页选中特定的Tab.主页是用FragmentTabHost + Fragment 实现。思路是通过startActivityForResult以及setResult() 以及requestCode作为标志位,是ReadActivity返回,因为还有其他的requestCode。再通过

FragmentTabHost的setCurrentTab(int index)方法切换Tab,我把该方法放置在了startActivityForResult()中,出现该问题java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState。

2.为什么?

  查阅源码,进入到FragmentManager的源码找到这么一段解释:

/**
     * Start a series of edit operations on the Fragments associated with
     * this FragmentManager.
     *
     * <p>Note: A fragment transaction can only be created/committed prior
     * to an activity saving its state.  If you try to commit a transaction
     * after {@link FragmentActivity#onSaveInstanceState FragmentActivity.onSaveInstanceState()}
     * (and prior to a following {@link FragmentActivity#onStart FragmentActivity.onStart}
     * or {@link FragmentActivity#onResume FragmentActivity.onResume()}, you will get an error.
     * This is because the framework takes care of saving your current fragments
     * in the state, and if changes are made after the state is saved then they
     * will be lost.</p>
     */
    public abstract FragmentTransaction beginTransaction();

大意是:一个fragment事务只能在该依附的Activity正在保存状态时创建(created)或者提交(committed ),如果在调用onSaveInstanceState()之后再提交事务,就会导致问题发生—— Can not perform this action after onSaveInstanceState 。

3. 发生的时机:

  先看FragmentManager中这么一段代码(只展示相关代码):(static final boolean HONEYCOMB = android.os.Build.VERSION.SDK_INT >= 11;)

Parcelable saveAllState() {
        // Make sure all pending operations have now been executed to get
        // our state update-to-date.
        execPendingActions();

        if (HONEYCOMB) {
            // As of Honeycomb, we save state after pausing.  Prior to that
            // it is before pausing.  With fragments this is an issue, since
            // there are many things you may do after pausing but before
            // stopping that change the fragment state.  For those older
            // devices, we will not at this point say that we have saved
            // the state, so we will allow them to continue doing fragment
            // transactions.  This retains the same semantics as Honeycomb,
            // though you do have the risk of losing the very most recent state
            // if the process is killed...  we‘ll live with that.
            mStateSaved = true;
        }
}

只看if中的注释:HONEYCOMB -> 大于等于Android3.0 版本的系统,Activity在不可见状态(pausing)后保存其状态,置mStateSaved状态为true。对于3.0更早的设备,则允许在不可见状态后执行fragment事务,所以保存状态就是不确定的了,但是肯定会在stop之前保存状态。

  mStateSaved(布尔值)标志是否保存状态:

private void checkStateLoss() {
        if (mStateSaved) {
            throw new IllegalStateException(
                    "Can not perform this action after onSaveInstanceState");
        }
        if (mNoTransactionsBecause != null) {
            throw new IllegalStateException(
                    "Can not perform this action inside of " + mNoTransactionsBecause);
        }
    }
static final boolean HONEYCOMB = android.os.Build.VERSION.SDK_INT >= 11;4. 思路整理:  从主页跳转到ReadActivity,MainActivity(首页)已不可见并且保存其状态,此时已经不能再对fragment执行commit操作。而FragmentTabHost的setCurrentTab(int index)中调用了commit方法,导致问题出现。setCurrentTab()  -> invokeOnTabChangeListener() -> onTabChanged() -> ft.commit();  一目了然!!!
 1 public void setCurrentTab(int index) {
 2         if (index < 0 || index >= mTabSpecs.size()) {
 3             return;
 4         }
 5
 6         if (index == mCurrentTab) {
 7             return;
 8         }
 9
10         // notify old tab content
11         if (mCurrentTab != -1) {
12             mTabSpecs.get(mCurrentTab).mContentStrategy.tabClosed();
13         }
14
15         mCurrentTab = index;
16         final TabHost.TabSpec spec = mTabSpecs.get(index);
17
18         // Call the tab widget‘s focusCurrentTab(), instead of just
19         // selecting the tab.
20         mTabWidget.focusCurrentTab(mCurrentTab);
21
22         // tab content
23         mCurrentView = spec.mContentStrategy.getContentView();
24
25         if (mCurrentView.getParent() == null) {
26             mTabContent
27                     .addView(
28                             mCurrentView,
29                             new ViewGroup.LayoutParams(
30                                     ViewGroup.LayoutParams.MATCH_PARENT,
31                                     ViewGroup.LayoutParams.MATCH_PARENT));
32         }
33
34         if (!mTabWidget.hasFocus()) {
35             // if the tab widget didn‘t take focus (likely because we‘re in touch mode)
36             // give the current tab content view a shot
37             mCurrentView.requestFocus();
38         }
39
40         //mTabContent.requestFocus(View.FOCUS_FORWARD);
41         invokeOnTabChangeListener();
42     }
43
44     /**
45      * Register a callback to be invoked when the selected state of any of the items
46      * in this list changes
47      * @param l
48      * The callback that will run
49      */
50     public void setOnTabChangedListener(OnTabChangeListener l) {
51         mOnTabChangeListener = l;
52     }
53
54     private void invokeOnTabChangeListener() {
55         if (mOnTabChangeListener != null) {
56             mOnTabChangeListener.onTabChanged(getCurrentTabTag());
57         }
58     }
59
60 @Override
61     public void onTabChanged(String tabId) {
62         if (mAttached) {
63             FragmentTransaction ft = doTabChanged(tabId, null);
64             if (ft != null) {
65                 ft.commit();
66             }
67         }
68         if (mOnTabChangeListener != null) {
69             mOnTabChangeListener.onTabChanged(tabId);
70         }
71     }

5. 解决:

  知道问题所在这就好说了,只要在Activity未保存状态之前执行setCurrentTab()方法,其关键就是执行commit方法。要么在当前未保存状态之前,要么在Activity再次可见并未onPause之前都是不会出问题的,哦了。

 
时间: 2024-11-06 03:50:51

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState的相关文章

Fragment java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

首先描述下所要实现的功能点: MainActivity使用Fragment实现底部菜单,底部共有四个菜单按钮,分别对应:AFragment,BFragment,CFragment,DFragment.其中AFragment是默认显示. 点击CFragment中的一个button后跳转到第二个Activity界面:SecondActivity. SecondActivity返回键有两个:button01.button02.其中button01返回的是CFragment:button02返回的是AF

bug java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

在有Fragment的Activity中开启Activity出现下面这个Exception: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceStateat android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1343)at android.support.v4.app.Frag

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState问题解决

(1)我用的是fragment,在onStop但是没有onDestroy的情况下切换(replace)fragment时报 java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState错误,出现问题原因,在于我使用了FragmentTransaction.commit,解决办法:使用FragmentTransaction.commitAllowingStateLoss就不会报错了 (2

解决dialogfragment在锁屏后建立不能建立问题IllegalStateException: Can not perform this action after onSaveInstanceState

今天使用Fragment的时候,出现了这个错误 IllegalStateException: Can not perform this action after onSaveInstanceState: E/AndroidRuntime(12747): Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState at android.support.v4.app

解决IllegalStateException: Can not perform this action after onSaveInstanceState:

今天做项目中的支付宝功能,是在fragment中做的,在支付成功后,想切换到支付成功的页面. 结果就报错了IllegalStateException: Can not perform this action after onSaveInstanceState: 在网上找了下解决方案,将commit改成了 commitAllowingStateLoss()就没问题了,贴出原帖地址http://www.ablanxue.com/prone_7000_1.html,参考. 今天使用Fragment的时

解决IllegalStateException: Can not perform this action after onSaveInstanceState

extends:http://blog.csdn.net/ranxiedao/article/details/8214936 , http://blog.csdn.net/top_code/article/details/12614571 今天使用Fragment的时候,出现了这个错误 IllegalStateException: Can not perform this action after onSaveInstanceState: E/AndroidRuntime(12747): Cau

Android - IllegalStateException: Can not perform this action after onSaveInstanceState

IllegalStateException: Can not perform this action after onSaveInstanceState 本文地址:http://blog.csdn.net/caroline_wendy 参考:http://stackoverflow.com/questions/7469082/getting-exception-illegalstateexception-can-not-perform-this-action-after-onsa/1026143

IllegalStateException: Can not perform this action after onSaveInstanceState 错误解决方法

使用handler 更新主activity中的碎片fragment是在使用FragmentTransition的 commit方法添加一个Fragment的时候报IllegalStateException: Can not perform this action after onSaveInstanceState. 问题原因: 因为 onSaveInstanceState方法 是在该Activity即将被销毁前调用,来保存Activity数据的,如果在保存完状态后再用commit方法给它添加Fr

IllegalStateException: Can not perform this action after onSaveInstanceState

今天做项目的导航框架的时候遇到一个bug,框架如上图所示: 这个bug很奇怪,第一次进入运行.无论你怎么点击都OK!但是,当你退出去再进来的时候点击就会报上面的错误!在网上找了找,像这样的一个错误会有千奇百怪的方式出现!但是,一句"该操作不能执行在onSaveInstanceState()之后"却是一样的.像这种错误不是通用的,它相当于是一个很大的错误集,里面有很多报错的方式! 下面分析一下我的错误: 我的这个侧滑的左侧点击任一个item就会在右边位置显示该item对应的内容.这个效果