關於dialog引起的IllegalArgumentException

錯誤日誌總髮現這個錯誤
java.lang.IllegalArgumentException: View=com.android.internal.policy.impl.PhoneWindow$DecorView{24933b1f V.E….. R…..I. 0,0-0,0} not attached to window manager

從字面意思是非法參數報錯,找到報錯的那一行發現是 dialog.dismiss()深入分析如下:
(1). 爲什麼報錯 com.android.phone 已停止運行?
通過查看網上資料可以知道,在原碼中在其 AndroidManifest.xml 可以發現: android:sharedUserId=”android.uid.phone” 也就是和 Phone 在一個進程中,因此在報錯的表現上來講就會是 PhoneWindow。

(2). 爲什麼會報 View not attached to window manager 錯誤?
這個錯誤的意思是說我們所操作的View沒有被納入 window manager 的管理。
我們知道所有的窗口創建和管理都是依附於window manager的,因此 Dialog 的創建也不例外。Dialog 的創建流程通過查看源碼可以知道,在Dialog的構造函數中,創建了一個 Window 對象,但我們知道 Window 對象並不是用於顯示的,真正用於顯示的是 View 對象。因此通過 Dialog 的 show 方法構造了一個 mDecor 的 View 對象,並最終通過 WindowManager 的 addView() 方法顯示Dialog。
比如在界面上顯示一個 Dialog,當任務處理結束後再 Dismiss Dialog。如果在 Dialog 顯示期間,該 Activity 因爲某種原因被殺掉且又重新啓動了,那麼當任務結束時,Dismiss Dialog 的時候 WindowManager 檢查,就會發現該 Dialog 所屬的 Activity 已經不存在了(重新啓動了一次,是一個新的 Activity),所以會報 IllegalArgumentException: View not attached to window manager.
通過以上分析我們可以知道在 Dialog 在執行 dismiss 方法時,發現啓動它的Activity已經不見了,被殺掉了(現在這個是重新啓動的),所以才報錯出現異常。

(3). 爲什麼Activity會被”殺掉”?
對於onSaveInstanceState方法,在Android SDK裏面有這樣的描述:Android calls onSaveInstanceState() before the activity becomes vulnerable to being destroyed by the system, but does not bother calling it when the instance is actually being destroyed by a user action (such as pressing the BACK key)
也就說當某個 activity 變得“容易”被系統銷燬時,該 activity 的 onSaveInstanceState 就會被執行,除非該activity是被用戶主動銷燬的,例如當用戶按 BACK 鍵的時候。注意這裏的容易二字,當前 Activity 並沒有被銷燬,只是系統覺得它有可能會被銷燬因此會執行該方法。在該方法中我們可以保存 Activity 中的各種 數據信息,如果該Activity真的被殺掉而又重新啓動後,可以使用 onRestoreInstanceState 方法在重新啓動該Activity 時,還原我們之前保存的數據信息。onSaveInstanceState 方法的調用遵循一個重要原則,即當系統“未經你許可”銷燬了你的 Activity 時,onSaveInstanceState 就會被系統調用,這是系統的責任,因爲它必須要提供一個機會讓你保存你的數據(當然如果你自 己不保存,那就沒法恢復了)。
因此通過以上分析我們可以看到 Activity 的確被殺掉後再次啓動了。

(4). 在 SActivity 被殺掉時,Dialog 存在麼?
可能大家會有疑問,Dialog 都沒有看到,就出現錯誤了,怎麼能確定該 Dialog 當時一定是顯示的呢?
其實 Activity 在被銷燬時,其所依附的 Dialog 是存在的。

(5). 如何解決這個問題呢?
通過以上分析之後我們知道了問題出現的原因,那麼如何解決呢?可以通過以下兩個方面來解決:

1.使用 Activity 自帶的 Dialog 控制方法
在 Activity 中需要使用對話框,可以使用 Activity 自帶的回調,比如 onCreateDialog(),showDialog(),dimissDialog(),removeDialog()等等。畢竟這些都是 Activity 自帶的方法,所以用起來更方便,也不用顯示創建和操控Dialog對象,一切都由框架操控,相對來說比較安全。
2.限制 Dialog 的生命週期
讓創建的 Dialog 對象的存活週期跟 Activity 的生命週期一致,也就是說 Dialog 的生命週期被限定在 Activity的 onCreate() 和 onDestroy() 方法之間。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章