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

來源:互聯網
上載者:User

標籤:getc   current   resume   ack   framework   roi   err   been   form   

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 content11         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 just19         // selecting the tab.20         mTabWidget.focusCurrentTab(mCurrentTab);21 22         // tab content23         mCurrentView = spec.mContentStrategy.getContentView();24 25         if (mCurrentView.getParent() == null) {26             mTabContent27                     .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 shot37             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 items46      * in this list changes47      * @param l48      * The callback that will run49      */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 @Override61     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之前都是不會出問題的,哦了。

 

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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.