WindowInspector (inspecteur de fenêtre) est sorti depuis deux ans, vous ne comprenez toujours pas ? ! !

Cet article a participé à l'activité Haowen Summoning Order, cliquez pour voir: les soumissions à double voie back-end et front-end, la cagnotte de 20 000 yuans vous attend pour défier!

avant-propos

Ce point de connaissance est sorti depuis deux ans, et maintenant je cherche sur Internet et je n'ai vu aucun partage pertinent. Une API très facile à utiliser, qui n'a été ajoutée que dans Android 10, pour résoudre un point douloureux de la fenêtre flottante. Permettez-moi de partager mon expérience avec vous, et j'espère qu'elle vous sera utile.

Point douloureux de la fenêtre flottante (la vue est jointe)

Pourquoi dites-vous "Le jugement de View est attaché est le point douloureux de la fenêtre flottante" ?

Avant Android 10

WinodwManager fournit des opérations addView et removeView.Il n'y a pas d'interface de requête.Comment juger si une vue est ajoutée ou non, la seule façon à laquelle je peux penser est la vue est attachée. L'ajout du journal de code source de "Vue non attachée au gestionnaire de fenêtres" rend les développeurs convaincus qu'en jugeant par View.isAttachedToWindow, il est possible de juger si la vue est sur la fenêtre, sans enquêter sur les risques éventuels d'utilisation.

Malheureusement, sans autres bonnes API, l'utilisation de View.isAttachedToWindow est devenue presque la seule option.

Android 10 pousse de nouvelles API, offrant aux développeurs un meilleur choix.

Utilisez un cas pour illustrer cette API et résoudre ce problème.

Examen de cas

Utilisation de fenêtres flottantes

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

Mais l'ajout ou la suppression peut facilement conduire à un crash, le journal est le suivant

Par exemple : la même vue est ajoutée deux fois

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)
复制代码

Supprimer une fenêtre sans attacher

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 solution habituelle : invites de journal non jointes -> utilisez simplement View.isAttachedToWindow pour juger le code comme suit :

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();
    }
}
复制代码

les problèmes rencontrés

En utilisant le code ci-dessus, mais il y a toujours une très faible probabilité de plantage dans le projet.

Autrement dit, isAttachedToWindow ≠ view est une fenêtre d'ajout

Résoudre le problème

  • Première option :

    应用中给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的范围是应用级别的,获取不到其他应用的窗口。

Je suppose que tu aimes

Origine juejin.im/post/6981476971394007054
conseillé
Classement