android Dialog dismiss crash 的 frameworks/base下的解决方案

从android 4.0到 9.0有不少做app的人遇到这个问题,google还没解决

目前在android 9上继承Dialog类的有8个类,app用得最多的是AlertDialog

现有看到的解决方案只是在app应用端规避,在创建Dialog(或者它的子类)时,保存句柄,在activity的生命周期函数onDestroy函数中调用句柄的dismiss函数

这个解法可以把crash概率降低1000倍,因为调整了时序逻辑

但还需要反思的有两个问题

1、在onDestroy管理所有dialog句柄,这样冗余的代码不可以优化吗?

2、应用层没办法trycatch这个由view抛出的crash,那么这个crash报得是否合理?

都有答案

1、Activity类里有一个变量mManageDialogs。管理着所有dialog的句柄,在onDestroy函数里,有遍历它然后把所有dialog调用一下dismiss。现在这个变量已经废弃了,因为自从android4.0版本,google把showDialog这个函数标志为废弃,所以Dialog句柄没有被添加到这个mManageDialogs里。

可以优化,可以做这两步:

a)可以在activity添加一个包方法(不写private\public\protect)addDialog(Dialog dialog),把传进来的dialog加到mManageDialogs里。

b)在Dialog类的show方法里,调用Activity类的addDialog方法,(Activity)mContext.addDialog(this),把dialog自己加到mManageDialogs里。

2、WindowManagerGlobal类的removeView函数里,在synchronized(mLock)后的第一件事是findViewLocked(view,true),这里就是报错的地方,意图是,我这个线程正准备向底层传达释放资源的信号,但是我却找不到我之前被加入到列表的痕迹,如果找不到的话,我就没办法释放底层相关的资源,会造成资源泄漏的,必须报出异常。

调用removeView函数时传进来的view其实有三种情形。第一,这个view之前从来没有被add过,没有底层资源。第二,这个view被add过然后已经操作过一次remove了。第三,这个view被add过,但没有被remove,但是现在在管理列表又找不到了。这个crash把三种情况都囊括了,不合理。除了第三种情况,前两种都不应crash。

可以优化,可以做这两步:

a)view里添加一个int变量 mDoneaddtoList ,初始值为0

b)WindowManagerGlobal里有三个函数要添加逻辑,addView/removeView/doRemoveView

 

frameworks/base优化参考如下

diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java

@@ -5054,6 +5054,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     private ContentCaptureSession mCachedContentCaptureSession;
 
     /**
+     * only use by WindowManagerGlobal
+     * set 1  when addView
+     * set 2 when doRemoveView
+     * check when removeView
+     */
+    int mDoneaddtoList = 0;
+
+    /**
      * Simple constructor to use when creating a view from code.
      *
      * @param context The Context the view is running in, through which it can
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java

--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -397,6 +397,7 @@ public final class WindowManagerGlobal {
             view.setLayoutParams(wparams);
 
             mViews.add(view);
+            view.mDoneaddtoList = 1;
             mRoots.add(root);
             mParams.add(wparams);
 
@@ -447,6 +448,10 @@ public final class WindowManagerGlobal {
         }
 
         synchronized (mLock) {
+            if(view.mDoneaddtoList == 2){
+                Log.d(TAG, "the view had been removed, no need to remove againt");
+                return;
+            }
             int index = findViewLocked(view, true);
             View curView = mRoots.get(index).getView();
             removeViewLocked(index, immediate);
@@ -527,6 +532,7 @@ public final class WindowManagerGlobal {
                 mRoots.remove(index);
                 mParams.remove(index);
                 final View view = mViews.remove(index);
+               view.mDoneaddtoList = 2;
                 mDyingViews.remove(view);
             }
         }

 

 

你可能感兴趣的:(android)