浮窗开发之窗口层级

最近在项目中遇到了这样的需求:需要在特定的其他应用之上悬浮自己的UI交互(拖动、输入等复杂的UI交互),和九游的浮窗类似,不过我们的比九游的体验更好,我们越过了很多授权的限制。


很多人都知道如何去实现一个简单的浮窗,但是却很少有人去深入的研究背后的流程机制,由于项目中浮窗交互比较复杂,遇到了些坑查看了很多资料,故总结浮窗涉及到的知识点:

  • 窗口层级关系(浮窗是如何“浮”的)?
  • 浮窗有哪些限制,如何越过用户授权实现浮窗功能?
  • 窗口与用户输入系统(Activity是如何接收到touch事件的)?

本章我们来研究第一个问题:浮窗为何会浮。浮窗之所以叫浮窗,是因为它能悬浮于应用或者桌面窗口之上,能脱离Activity而存在。为了研究其中区别,我们先来看看我们最熟悉的Activity是怎么显示出来的。

Activity是怎么显示出来的?

要弄清这个问题答案,我们先从Activity的setContentView()这个方法的源码开始找起,在Activity中看到setCententView的源码:

public void setContentView(int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

getWindow是返回返回Activity的mWindow变量,指向一个Window的对象,Window是一个抽象类,这里返回的是PhoneWindow对象(PhoneWindow是Window的子类),PhoneWindow中有一个DecorView对象,decorView成员,这是一个FrameLayout,setContentView的子布局最终会添加到decorView中,这个decorView就是当前窗口的根视图,这个根视图是如何最终被绘制出来的?在ActivityThread中有这样一段代码:

            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
            l.softInputMode |= forwardBit;
            if (a.mVisibleFromClient) {
                a.mWindowAdded = true;
                wm.addView(decor, l);
            }

这个decorView,最终会被WindowManager.addView添加到绘制系统中,并类型是WindowManager.LayoutParams.TYPE_BASE_APPLICATION,这个参数决定了要绘制的窗口的z轴层次,为了避免思维栈过深,这里就不贴出详细的源码跟踪过程了,直接给结论。
先来看看Activity和window的关系:


再来window和View的关系:

Activity窗口显示过程:


说Activity是怎么显示出来的,其实是说Activity管理的View是怎么显示出来的。最后再来总结一下:

一、Activity通过setContentView设置的视图是添加到PhoneWindow的根视图decor中。

二、Window是一个抽象的概念,Window关了了一个View(根视图),最终被WindowManager管理的还是一个View(根视图)和它的LayoutParams,视图绘制刷新都是通过WindowManager(WindowManagerGlobal)与WindowManagerServiceIPC交互调用底层绘制的。

三、Activity是四大组件中唯一和窗体紧密联系的组件(这是为什么会有初学者把Activity直接理解为绘制界面的原因),所有掌管的视图只不过是一种window和Dialog、Toast、墙纸所掌管的Window类型不一样。

浮窗为什么会“浮”?

上面讲到Activity的显示过程其实已经揭示了通用界面的显示过程,浮窗的显示过程更为简单:


做过浮窗的同学应该都明白了,为啥浮窗能脱离Activity而显示,本质上我们是把一个View交给WindowManager来管理了,LayoutParams.type类型决定了这个View显示窗口的类型,不同类型显示的窗口层次(z轴)是不一样的。大方面来讲可以分为应用窗口(APPLICATION_WINDOW)、子窗口(SUB_WINDOW)、系统窗口(SYSTEM_WINDOW)三种类型,应用窗口z轴范围是1~99,子窗口的范围是1001~1999,系统窗口是(2000~2999),所以要实现浮动窗口我们只能在系统窗口范围中实现。


到这里我们对Android系统的窗口层次有个大致的了解了,Activity是Android应用的四大组件之一,描述的是应用的活动状态和周期,受ActivityManagerService的管理;Window/View是图形窗口的抽象模型,描述的是窗口的绘制信息,受WindowManagerService的管理;Activity聚合Window来和图形窗口产生联系。文章旨在理解一下Android窗体系统的一个雏形,能力有限不能详细跟踪整个窗口体系的源码,有兴趣的可以自己深入,下一篇文章:《越过授权使用浮窗》。

作者声明:本人只在简书、云栖和本人博客中发表文章,转载需联系本人取得同意!读者阅读时若出现排版混乱、广告等影响阅读体验说明不是原文,建议到简书、云栖或本人博客中阅读原文以取得更好的阅读体验。

时间: 2024-09-10 06:18:44

浮窗开发之窗口层级的相关文章

浮窗系列之窗口与用户输入系统

在<浮窗开发之窗口层级>这篇文章中,开篇提出了三个问题: 窗口层级关系(浮窗是如何"浮"的)? 浮窗有哪些限制,如何越过用户授权实现浮窗功能? Activity是如何接收到touch事件的? 前两个问题在前两篇文章中已经分析,在这篇文章中我们以第三个问题为切入点,简单分析一下窗口与用户输入的关系. Touch事件是如何分发到Activity上来的? 正常的思路是直接去寻找Activity 的dispatchTouchEvent方法,我们看看Activity的dispatch

浮窗系列之越过授权使用浮窗

上一片篇文章分析了浮窗系列之Android窗口系统层次.Ativity的窗口和系统窗口的区别,这篇文章我来说说使用系统窗口来实现浮窗的一些限制,我们如何越过这些限制? 简单的浮窗实现 final WindowManager windowManager = getWindowManager(context); //创建自定义浮窗 FloatView hideDialog = new FloatView(context); WindowManager.LayoutParams params = ne

三星GALAXY A7(A7009)多窗口中将全屏模式转为浮窗模式教程

注意:多窗口中将全屏模式转为浮窗模式是手机支持并且应用程序也要支持,如果有一些应用程序不支持出式窗口的话,那么我们设置也是无效的. 下面我们以这里以"三星应用商店"为例子吧. 1.如下图所示我们在手机中沿屏幕左上角或右上角的对角线方向拖动屏幕的某个角   2.然后我们只要点击弹出式窗口的[圆点]图标可以查看更多选项 如下图所示.    3,进入更多选项之后我们就可以对窗口进行 拖动内容.最小化窗口.最大化窗口.关闭应用程序,这里以点击[最小化窗口]图标为例."三星应用商店&q

三星N9150在多窗口中如何将全屏模式转为浮窗模式

如下所示我们从手机屏幕的对角线的方向然后用手指拖动屏幕的左上角 然后就会直接把窗口转换成弹出式窗口了,如下面小编以"我的剪贴库"为例   2.然后在弹出的窗口界面中我们点击[圆点]就可以查看更多更好选项.    3.之后在打开的图标中我们就可以选择:拖放内容.最小化窗口.最大化窗口.关闭应用程序,这里以点击[最小化窗口]图标为例.    4."我的剪贴库"以一个圆形的浮动图标出现在屏幕上.    好了到了这里关于浮窗模式就介绍完成了,希望例子可以帮助到各位.

百度统计最新高级功能让浮窗无所遁形!

&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp;   百度统计专为高级用户推出最新高级功能,可以监控各种浮窗.只需简单设置,就能帮你监控各种浮窗-商务通.乐语.登录窗口.此项功能非常实用,比如监控"咨询按钮"的浮窗,可以知道有多少人点击了咨询按钮,进行咨询:再比如监控"登录窗口",可以知道多少人点击了登录窗口,其中普通登录有多少人,手机登录又有多少人 我们为此专门制作了一期专

百度统计推出高级功能,让浮窗无所遁形

百度统计专为高级用户推出最新高级功能,可以监控各种浮窗.此功能只需安装一段代码即可实现,我们将这段代码命名为转化分析代码,而如何安装与使用这段代码,下面将给出详细介绍. 1.&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp;转化分析代码介绍 1.1 转化分析代码是什么 转化分析代码是百度统计最新开发统计代码,作为目前百度统计已有的访问分析代码的补充,可以被部署在客户网站的某些页面上,用来对某些特殊场景进行数据监控,以

仿360在Launcher画面显示内存使用率的浮窗(改进版)

MainActivity如下: package cc.cc; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.app.Activity; import android.content.Context; import android.content.Intent; /**

仿360在Launcher画面显示内存使用率的浮窗(基础版)

MainActivity如下: package cc.cc; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.app.Activity; import android.content.Context; import android.content.Intent; /**

jQuery简单实现中间浮窗效果_jquery

本文实例讲述了jQuery简单实现中间浮窗效果.分享给大家供大家参考,具体如下: basic.css: /* * -- 样式说明 -- * 最大优先实现法,全局能实现不用区域,区域能实现不用模板,模板能实现不用界面,界面能实现不用标签 * g - 全局 * t - 区域 * m - 模板 * ui - 界面 * lb - 标签 * j - 脚本 只使用在有JS操作的样式 */ /*公共样式*/ html, body, div, span, object, iframe, h1, h2, h3,