關於dialog引起的 java.lang.IllegalArgumentException: View=com.android.internal.policy.impl.PhoneWindow$DecorView not attached to window manager 錯誤的分析


在跑Monkey測試的時候出現了一個比較特別的問題,先來看看Log:

 1 // CRASH: com.meizu.media.painter (pid 12491)
 2 
 3 // Short Msg: java.lang.IllegalArgumentException
 4 
 5 // Long Msg: java.lang.IllegalArgumentException: View=com.android.internal.policy.impl.PhoneWindow$DecorView{21dd6762 V.ED.... R......D 0,0-538,105} not attached to window manager
 6 
 7 // Build Label: ***
 8 
 9 // Build Changelist: 1443062570
10 
11 // Build Time: 1443062722000
12 
13 // java.lang.IllegalArgumentException: View=com.android.internal.policy.impl.PhoneWindow$DecorView{21dd6762 V.ED.... R......D 0,0-538,105} not attached to window manager
14 
15 // at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:416)
16 
17 // at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:342)
18 
19 // at android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.java:116)
20 
21 // at android.app.Dialog.dismissDialog(Dialog.java:354)
22 
23 // at android.app.Dialog.dismiss(Dialog.java:337)
24 
25 // at com.***.***.***.PainterDrawActivity.closeProgressDialog(PainterDrawActivity.java:60)
26 
27 // at com.***.***.painter.PainterDrawActivity.access$000(PainterDrawActivity.java:28)
28 
29 // at com.***.***.painter.PainterDrawActivity$1$2.run(PainterDrawActivity.java:49)
30 
31 // at android.os.Handler.handleCallback(Handler.java:815)
32 
33 // at android.os.Handler.dispatchMessage(Handler.java:104)
34 
35 // at android.os.Looper.loop(Looper.java:194)
36 
37 // at android.app.ActivityThread.main(ActivityThread.java:5741)
38 
39 // at java.lang.reflect.Method.invoke(Native Method)
40 
41 // at java.lang.reflect.Method.invoke(Method.java:372)
42 
43 // at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:980)
44 
45 // at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:775)
46 
47 //

從上面的Log可以看出是一個非法參數異常的問題。

那為什么會出現Long Msg: java.lang.IllegalArgumentException: View=com.android.internal.policy.impl.PhoneWindow$DecorView{21dd6762 V.ED.... R......D 0,0-538,105} not attached to window manager的問題呢?應用本身的崩潰怎么會聯系到

PhoneWindow呢?

(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。
       通過查看log信息我們可以看到PainterDrawActivity.closeProgressDialog(PainterDrawActivity.java:60)查看對應的closeProgressDialog代碼后發現,在60行處代碼為dialog.dismiss();
       在網絡上搜索后發現,多數情況下出現這種錯誤,都是在dismiss Dialog時,發現創建該Dialog的Activity存在而導致的。
比如在界面上顯示一個 Dialog,當任務處理結束后再Dismiss Dialog。如果在Dialog顯示期間,該Activity因為某種原因被殺掉且又重新啟動了,那么當任務結束時,Dismiss Dialog的時候WindowManager檢查,就會發現該Dialog所屬的Activity已經不存在了(重新啟動了一次,是一個新的 Activity),所以會報IllegalArgumentException: View not attached to window manager.
通過以上分析我們可以知道在Dialog在執行dismiss方法時,發現啟動它的Activity已經不見了,被殺掉了(現在這個是重新啟動的),所以才報錯出現異常。

(3). 為什么Activity會被"殺掉"?

由於是Monkey測試出現一次的Log,我們很難復現,只能從網上遇到類似問題的人看看他們的看法。

對於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()方法之間。

 

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM