WindowInspector (inspector de ventanas) ha estado fuera durante dos años, ¿aún no lo entiendes? ! !

Este artículo ha participado en la actividad Haowen Summoning Order, haga clic para ver: las presentaciones de doble vía de back-end y front-end, ¡el pozo de premios de 20,000 yuanes lo está esperando para desafiarlo!

prefacio

Este punto de conocimiento ha estado fuera durante dos años, y ahora busco en Internet y no he visto ningún intercambio relevante. Una API muy fácil de usar, que solo se agregó en Android 10, para resolver un punto débil de la ventana flotante. Déjame compartir mi experiencia contigo y espero que te sea útil.

Punto de dolor de la ventana flotante (Ver adjunto)

¿Por qué dices "El juicio de View está adjunto es el punto de dolor de la ventana flotante"?

Antes de Android 10

WinodwManager proporciona operaciones addView y removeView. No hay interfaz de consulta. Cómo juzgar si una vista se agrega o no, la única forma en que puedo pensar es ver adjuntar. Agregar el registro de código fuente de "Vista no adjunta al administrador de ventanas" hace que los desarrolladores se convenzan de que, al juzgar por View.isAttachedToWindow, es posible juzgar si la vista está en la ventana, sin investigar los posibles riesgos en uso.

Lamentablemente, sin otras buenas API, usar View.isAttachedToWindow se ha convertido casi en la única opción.

Android 10 impulsa nuevas API, lo que brinda a los desarrolladores una mejor opción.

Use un caso para ilustrar esta API y resolver este problema.

Revisión de caso

Uso de ventanas flotantes.

windowManager.addView(view, layoutParams);//新增窗口
windowManager.removeView(view);移除窗口
复制代码

Pero agregar o eliminar puede provocar fácilmente un bloqueo, el registro es el siguiente

Tales como: la misma vista se agrega dos veces

05-21 03:19:13.285 3463 3463 W System.err: java.lang.IllegalStateException: View XXX{7afdd92 V.E...... ......I. 0,0-56,290} has already been added to the window manager.

05-21 03:19:13.285 3463 3463 W System.err:  at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:359)

05-21 03:19:13.285 3463 3463 W System.err:  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:96)
复制代码

Eliminar una ventana sin Adjuntar

W System.err: java.lang.IllegalArgumentException: View=XXXX{25626d6 V.E...... ........ 0,0-56,229} not attached to window manager

08-19 07:08:08.832 25836 25836 W System.err:   at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:517)

08-19 07:08:08.832 25836 25836 W System.err:   at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:426)

08-19 07:08:08.832 25836 25836 W System.err:   at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:123)
复制代码

La solución habitual: las indicaciones de registro no están adjuntas -> solo use View.isAttachedToWindow para evaluar el código de la siguiente manera:

if(view.isAttachedToWindow()){
    try {
        windowManager.removeView(textView);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
if(!view.isAttachedToWindow()){
    try {
        windowManager.addView(view,layoutParams);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
复制代码

problemas encontrados

Usando el código anterior, pero todavía hay una probabilidad muy baja de bloqueo en el proyecto.

Es decir, isAttachedToWindow ≠ vista es agregar ventana

Resolver el problema

  • Opcion uno:

    应用中给View标志位,表示view 是否被add。但是总觉得本地标识,没有系统api准确,该方案不算太好。偶现的问题,必然有必现的过程,后面进行了深入的分析。

    项目中遇到的问题是:同一个view,windowManager.addView 被连续执行了两次,也不是异步造成的。

    最后发现,两次调用时间间隔极短,isAttachedToWindow 还没有来得及改变。

    经详细调查有了方案二。

  • 方案二:

    使用 WindowInspector,此类在Android 10 framework 才增加,且只有getGlobalWindowViews 这一个静态方法

    view.isAttachedToWindow() 改为 WindowInspector.getGlobalWindowViews().contains(view)
    复制代码

源码分析

getGlobalWindowViews

看下主要类的调用关系,以及主要的方法

RmzUoV.png

/**
* addView 与 removeView 都会调用此方法
* addView  required:false 如果 index !=0  同一个View重复add,抛异常
* removeView required:true  index < 0 ,没有找到View,抛异常
*/
private int findViewLocked(View view, boolean required) {
    final int index = mViews.indexOf(view);
    if (required && index < 0) {
        throw new IllegalArgumentException("View=" + view + " not attached to window manager");
    }
    return index;
}
复制代码

通过以上分析:WindowManagerGlobal 中 mView 是问题的关键,管理着所属应用的所有View。

Android 10,提供了 WindowInspector.getGlobalWindowViews()。可以获取mViews。修改代码如下

if(WindowInspector.getGlobalWindowViews().contains(view)){
    windowManager.removeView(view);
}
if(!WindowInspector.getGlobalWindowViews().contains(view)){
    windowManager.addView(view,layoutParams);
}
复制代码

分析到这里,问题就解决了。那isAttachedToWindow 怎么就不行呢?

isAttachedToWindow

以下时序图看出:

当刷新线程走完后,才认为是attach。

在这里插入图片描述

两者区别是:attach 当view 被add ,且被刷新了。

总结

经过上文分析,从view add -> attach , 区别是view 是否被刷新。

分析了下:为什么要重新用WindowInspector,而不是用WIndowManager WindowManager:是对Window 的管理,查询觉得不合适吧,所以用了WindowInspector类

下面说明下可能出现的一些误区

1、getGlobalWindowViews 获取的View列表 ,其实是WindowManagerGlobal.mViews 的浅拷贝,所以增删改,都不会应该WindowManagerGlobal 中mViews的结构。

2、强调下,不要被Global迷惑,Global的范围是应用级别的,获取不到其他应用的窗口。

Supongo que te gusta

Origin juejin.im/post/6981476971394007054
Recomendado
Clasificación