不使用Activity如何添加一个View

2,628 阅读3分钟

WindowManger详解

更新

直播回放已放出,请戳链接食用:不使用Activity如何添加一个View

整体方案

在Service中通过WindowManger添加View的方式来把UI界面显示出来

业务场景

具体场景

  • IQOO手机,游戏辅助

这种场景能否使用Activity方式来做

使用activity会对下层window产生阻塞,而使用WindowManager添加view的方式则不会阻塞

WindowManger简介

WindowManger是普通App进程用来与系统服务(WindowMangerService)通信的一个接口。 获取WindowManger实例对象的方法是使用Context.getSystemService(Context.WINDOW_SERVICE

如何使用

  1. 添加权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
  1. 手动引导开启显示在其他应用上层

  2. 获取WindowManger并添加View

WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); //获取系统服务
windowManager.addView(myView, p);
  1. 不使用时移除View

WindowManager使用详解

WindowManger

  1. 添加View :addView()

    注意 同一个window,只能添加一个View,添加多个View会报出以下异常

Caused by: java.lang.IllegalStateException: View android.widget.RelativeLayout{b3a2c6a V.E...... ......I. 0,0-0,0 #7f070081 app:id/rl_root} has already been added to the window manager.
  1. 移除View : remoview()

由于同一个View只能添加一个View,所以,要想在已添加View的Window中再添加View,必须先移除已添加的View

  1. 更新布局属性 :updateViewLayout(view,params)

通过对第二个参数WindowManger.LayoutParams的属性设置后,调用本方法才会使这些属性生效

WindowManger.LayoutParms

WindowManger.LayoutParms 其实是ViewGrop.LayoutParms的子类对象,所以View设置LayoutParams时可以直接设置

  1. 控制是否可以响应触摸事件

    layoutParams.type

    • FLAG_NOT_TOUCHABLE
    • FLAG_NOT_TOUCH_MODAL
  2. 控制window的显示层级

    layoutParams.type

    • TYPE_TOAST(Andorid 5.0及以下系统版本可规避权限问题)
    • TYPE_APPLICATION_WINOW (应用层Winow等级)
    • TYPE_PRIORTY_PHONE (系统层Window等级)
  3. 控制view的显示范围

    layoutParams.flags

    • FLAG_FULLSCREEN
    • FLAG_LAYOUT_IN_SCREEN
  4. 控制view的显示位置
    • layoutParams.width
    • layoutParams.height

示例项目

github.com/happyburgla…

还要注意哪些问题?

  1. 使用单独进程,避免影响主业务功能
  2. 提升进程优先级,避免被Kill
    • 使用前台服务
    • 1像素保活
    • 绑定系统服务

    提示:可通过oom_adj查看某个进程的进程等级

  3. 要对服务被Kill后的重启逻辑进行处理

源码浅析

由于时间关系,这里我们只对相关源码进行一个简单的介绍,先来看下相关的类

WindowManger这个类,其实只是一个接口,用来沟通普通应用进程和系统服务WindowMangerservice

我们在上面的使用中也看到了,获取WindowManger这个类的实例对象,是通过Context.getSystemServer(Context.WINDOW_SERICE)获取的

通过上面的UML类图我们也可以看到,其实WindowManger是一个接口,而它的真正的实例对象是WindowMangerImpl这个类

WindowMangerImpl又把具体的添加View的工作封装到了WindowManagerGlobal中来操作,这个类中又涉及到了另外一个重要的类--Display,这个类主要是封装了一些显示相关的信息,比如window的逻辑宽显示数据(logical displays)和物理显示数据(physical displays)

什么是logical displays

源码中对此解释是,逻辑显示不一定代表特定的物理显示设备,例如内置屏幕或外接显示器。 逻辑上的内容根据设备的不同,显示屏可以显示在一个或多个物理显示屏上

什么是physical displays

就是Android设备屏幕的真实的Displays数据,比如你的手机是4K的屏幕(physical displays),但是厂商为了进行一些优化工作(比如省电?)可以把显示尺寸(logical displays)设置为1920* 1080

郑重声明

本文版权归Android研习社所有,未经允许禁止转载,侵权必究!