Android - java.lang.IllegalStateException 剖析

以下堆棧信息日志是常見的illegalStateExecption日志。筆者是當(dāng)應(yīng)用出于后臺時,網(wǎng)絡(luò)響應(yīng)更新fragment時出現(xiàn)以下問題体箕。本文將對該異常拋出的的時間和原因進(jìn)行解釋,并對如何避免異常的發(fā)生提出一些意見。

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
    at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1341)
    at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1352)
    at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
    at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)

異常出現(xiàn)的原因

根據(jù)日志消息脾歇,顧名思義,該異常發(fā)生的原因是在Activity的state已經(jīng)被保存之后仍然試圖調(diào)用commit去提交FragmentTransaction. 在詳細(xì)解析這句話真正意思之前淘捡,讓我們首先了解一下究竟onSaveInstance里做了什么藕各。安卓系統(tǒng)隨時可能殺死進(jìn)程來釋放內(nèi)存,后臺Activity可能隨時被殺死焦除。因此Framework通過調(diào)用onSaveInstanceState( ) 來保存activity的狀態(tài)State. FrameWork通過Bundle對象來保存state, 其中記錄下dialog,fragment,view等視圖結(jié)構(gòu)和狀態(tài)激况。這樣即便Activity因?yàn)楫惓G闆r被系統(tǒng)殺死,還是可以通過保存下了的狀態(tài)來恢復(fù)原來的視圖膘魄。

了解了onSaveInstance具體做了什么之后乌逐,再來討論為什么onSaveInstance被調(diào)用之后不能調(diào)用commit.原因就是,onSaveInstance已經(jīng)用Bundle對象將Activity所有狀態(tài)視圖信息保存下來了创葡,這時候想要把這個事務(wù)提交上去是不可能的浙踢,安卓開發(fā)團(tuán)隊(duì)出于保護(hù)用戶界面不被影響,不惜一切代價防止保存的狀態(tài)不丟失灿渴,因此采用拋出異常的方式來解決洛波。聽起來有點(diǎn)抽象胰舆,其實(shí)可以通過一個例子來理解,全班同學(xué)的卷子都已經(jīng)上交并且批改結(jié)束蹬挤,分?jǐn)?shù)排名都出來了缚窿。這時候你再提交卷子肯定是不行的,誰知道你有沒有偷抄焰扳,如果你偷抄的話豈不是影響了班級的排名倦零。

什么時候會拋出異常

如果你之前已經(jīng)遇到過這樣的異常,可能已經(jīng)注意到在不同的安卓版本上異常拋出的可能性不一樣吨悍。例如扫茅,老的版本拋出異常的概率更小畜份;或者如果應(yīng)用程序使用support library時拋出異常的概率更大诞帐。這會讓人覺得是不是support library 有問題。然而事實(shí)上不是如此爆雹。

拋出異常的概率不同主要原因是Android3.0(HoneyComb)其之后版本中Activity生命周期的顯著差異造成的停蕉。在3.0以前,onSaveInstance是在onPause調(diào)用之前調(diào)用钙态,而3.0以后onSaveInstance是在onStop調(diào)用之前調(diào)用的慧起,這樣的話3.0以前在onSaveInstance之后調(diào)用commit的概率更高了,因此異常發(fā)生的概率也就更高了册倒。

如何避免異常發(fā)生

當(dāng)理解了異常發(fā)生背后的真相之后蚓挤,如何避免就輕而易舉了。

  • 在Activity生命周期中調(diào)用commit一定要注意驻子。
    盡量只在onCreate中調(diào)用commit.如果冒險(xiǎn)在其他生命周期回調(diào)函數(shù)中調(diào)用commit,例如onActivityResult(),onStart(),onResume,就很有可能出問題灿意。例如在onResume中調(diào)用commit,由于此時activity的狀態(tài)信息還沒有恢復(fù),就會拋出異常崇呵。如果一定要在其他生命周期中調(diào)用commit,可以在onResumeFragments或者在onPostResume中調(diào)用缤剧。這兩個方法可以保證activity的狀態(tài)信息已經(jīng)恢復(fù)了。
  • 避免在異步回調(diào)中調(diào)用commit.
    包括AsyncTask.onPostExecute()和LoaderManager.LoaderCallbacks.onLoadFinished().因?yàn)樵谶@些回調(diào)中調(diào)用commit時域慷,不知道當(dāng)前activity的生命周期走到哪一步荒辕,不知道是否當(dāng)前Activity的狀態(tài)信息是否已經(jīng)被保存。下面通過一個事件序列來說明:
    1.一個Activity執(zhí)行了一個AsyncTask.
    2.點(diǎn)擊Home鍵犹褒,此時onSaveInstanceState和onStop被調(diào)用
    3.AsyncTask完成調(diào)用onPostExecute,但是并不知道此時activity已經(jīng)結(jié)束
    4.在onPostExcute中調(diào)用commit,將導(dǎo)致異常拋出
    總的來說抵窒,避免異常的最好方法是避免在異步回調(diào)中調(diào)用commit。
  • 使用 commitAllowingStateLoss()
    commit和commitAllowingStateLoss的不同之處在于后者不會拋出異常叠骑,即使?fàn)顟B(tài)發(fā)生丟失李皇。通常情況下不應(yīng)該使用這個方法,因?yàn)檫@會導(dǎo)致activity的狀態(tài)信息丟失座云。因此最好的方法還是在保證activity的狀態(tài)信息被保存之前調(diào)用commit.
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末疙赠,一起剝皮案震驚了整個濱河市付材,隨后出現(xiàn)的幾起案子朦拖,更是在濱河造成了極大的恐慌圃阳,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件璧帝,死亡現(xiàn)場離奇詭異捍岳,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)睬隶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進(jìn)店門锣夹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人苏潜,你說我怎么就攤上這事银萍。” “怎么了恤左?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵贴唇,是天一觀的道長。 經(jīng)常有香客問我飞袋,道長戳气,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任巧鸭,我火速辦了婚禮瓶您,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘纲仍。我一直安慰自己呀袱,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布郑叠。 她就那樣靜靜地躺著夜赵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪锻拘。 梳的紋絲不亂的頭發(fā)上油吭,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天,我揣著相機(jī)與錄音署拟,去河邊找鬼婉宰。 笑死,一個胖子當(dāng)著我的面吹牛推穷,可吹牛的內(nèi)容都是我干的心包。 我是一名探鬼主播,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼馒铃,長吁一口氣:“原來是場噩夢啊……” “哼蟹腾!你這毒婦竟也來了痕惋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤娃殖,失蹤者是張志新(化名)和其女友劉穎值戳,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體炉爆,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡堕虹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了芬首。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赴捞。...
    茶點(diǎn)故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖郁稍,靈堂內(nèi)的尸體忽然破棺而出赦政,到底是詐尸還是另有隱情,我是刑警寧澤耀怜,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布恢着,位于F島的核電站,受9級特大地震影響封寞,放射性物質(zhì)發(fā)生泄漏然评。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一狈究、第九天 我趴在偏房一處隱蔽的房頂上張望碗淌。 院中可真熱鬧,春花似錦抖锥、人聲如沸亿眠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纳像。三九已至,卻和暖如春拯勉,著一層夾襖步出監(jiān)牢的瞬間竟趾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工宫峦, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留岔帽,地道東北人。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓导绷,卻偏偏與公主長得像犀勒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,781評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 今日是進(jìn)入實(shí)訓(xùn)中心上的第一堂網(wǎng)絡(luò)營銷課程贾费,這堂課讓我初步的了解到了網(wǎng)絡(luò)營銷這么專業(yè)钦购,我相信大多數(shù)人都認(rèn)為網(wǎng)絡(luò)營銷...
    魏湘粵閱讀 238評論 2 3
  • 2017.8.10
    cyxdac閱讀 145評論 0 0
  • 突然在朋友圈看到這張圖片,感覺無比溫暖褂萧,我是一個愛狗人士押桃,每當(dāng)朋友家有“新朋友”到來,我常會去會會這些機(jī)靈的小生靈...
    方政博閱讀 766評論 0 1
  • 內(nèi)在的紀(jì)律 今天是二月的最后一天箱玷,也是應(yīng)童老師帶領(lǐng)的第一期“心靈寫作實(shí)戰(zhàn)營”打卡活動的最后一天怨规。 寫下這一篇小文陌宿,...
    綿綿雨絲閱讀 709評論 2 0