Dialog 使用的常见坑.
- dismiss 错误堆栈
1 2 3 4 5
| java.lang.IllegalArgumentException View=DecorView@984ba6d[MainActivity] not attached to window manager android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:619) android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:511) android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.java:200) android.app.Dialog.dismissDialog(Dialog.java:766)
|
这里查看堆栈是 DIalog dismiss 的堆栈, 但是一般看不到调用 dialog.dismiss 的业务堆栈.
主要是因为这种情况下一般是子线程调用了 dismiss, 但是 Dialog 的 dismiss 会有一个切线程的操作:
1 2 3 4 5 6 7 8
| @Override public void dismiss() { if (Looper.myLooper() == mHandler.getLooper()) { dismissDialog(); } else { mHandler.post(mDismissAction); } }
|
其中 mHandler 对象是在 Dialog 创建的时候初始化的, 所以 Looper 也是和创建 Dialog 的时候的线程绑定的, 同时因为 Handler 是 private 的, 所以目前想到的 hook 方式是自己同步创建一个 Handler , 在调用 dismiss 时自己切线程, 这样就可以正确 try catch 这个 Exception.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class MyDialog(context: Context): Dialog(context) {
private val handler = Handler()
override fun dismiss() { if (Looper.myLooper() == handler.looper) { superDismiss() } else { handler.post { superDismiss() } } }
private fun superDismiss() { try { super.dismiss() } catch (e: Exception) { } } }
|