天天看點

onSaveInstanceState問題分析

産生的現象

我們在測試app的時候,有時候會碰到這樣的問題”java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState”,具體的狀況如下圖所示

onSaveInstanceState問題分析

一般出現在我們往activity容器裡面添加Fragment,或者是Fragment之間進行切換的時候比較容易出現這樣的問題。

問題的原因及複現

首先我們看如何複現這個問題,如以下代碼所示,建立activity,5秒鐘之後,往activity裡面添加Fragment。在這5秒之内按下home鍵,然後等待handler代碼執行,接着就可以看到log裡面報出“onSaveInstanceState”的錯誤了。

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test);

        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                Fragment fragment = new TestFragment();
                showFragment(fragment,"first");
            }
        },);


    }

    private void showFragment(Fragment fragment,String tag){
        FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.container, fragment, tag);
        ft.addToBackStack(null);
        ft.commit();
    }
           

為什麼會出現這個問題呢,我們可以通過log稍微的追蹤以下源碼。打開log裡面爆出這個錯誤的連結,可以發現,爆出這個異常的是checkStateLoss()函數,當mStateSaved為true時,就會抛出這個異常。

onSaveInstanceState問題分析
onSaveInstanceState問題分析

繼續追蹤就會發現,當activity執行onSaveInstance()的時候,就會将mStateSaved置為true。是以對于剛才的場景,當我們按下home鍵,activity會自動的執行到onSaveInstance,此時再執行commit函數,就會爆出這樣的異常了。有時候當我們快速進行切換,或者跑一些自動測試腳本的時候,就有可能會出現這個問題。

解決問題

其實這個問題挺好解決的,隻需要将commit換成commitAllowingStateLoss就可以了

onSaveInstanceState問題分析

官方給出的解釋如下

commitAllowingStateLoss
added in API level 

public abstract int commitAllowingStateLoss ()

Like commit() but allows the commit to be executed after an activity's state is saved.
This is dangerous because the commit can be lost 
if the activity needs to later be restored from its state,
so this should only be used for cases where it is okay for the UI state to change unexpectedly on the user. 
           

commitAllowingStateLoss與commit差不多,但有可能會導緻狀态的丢失。不過目前我還沒有遇到過狀态丢失的情況。