Android 浮窗开发之窗口层级
很多人都知道如何去实现一个简单的浮窗,但是却很少有人去深入的研究背后的流程机制,由于项目中浮窗交互比较复杂,遇到了些坑查看了很多资料,故总结浮窗涉及到的知识点:
- 窗口层级关系(浮窗是如何“浮”的)?
- 浮窗有哪些限制,如何越过用户授权实现浮窗功能?
- 窗口与用户输入系统(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),所以要实现浮动窗口我们只能在系统窗口范围中实现。
| 类型 | 常量范围 | 子类 | 常量值 | 说明 | 例子 |
| APPLICATION_WINDOW | 1~99 | TYPE_BASE_APPLICATION | 1 | ||
| TYPE_APPLICATION | 2 | 应用窗口 | 大部分的应用程序窗口 | ||
| TYPE_APPLICATION_STARTING | 3 | 应用程序的Activity显示之前由系统显示的窗口 | |||
| LAST_APPLICATION_WINDOW | 99 | ||||
| SUB_WINDOW | 1000~1999 | FIRST_SUB_WINDOW | 1000 | ||
| TYPE_APPLICATION_PANEL | 1000 | 显示在母窗口之上,遮挡其下面的应用窗口。 | |||
| TYPE_APPLICATION_MEDIA | 1001 | 显示在母窗口之下,如果应用窗口不挖洞,即不可见。 | SurfaceView,在小窗口显示时设为MEDIA, 全屏显示时设为PANEL | ||
| TYPE_APPLICATION_SUB_PANEL | 1002 | ||||
| TYPE_APPLICATION_ATTACHED_DIALOG | 1003 | ||||
| TYPE_APPLICATION_MEIDA_OVERLAY | 1004 | 用于两个SurfaceView的合成,如果设为MEDIA,则上面的SurfaceView 挡住下面的SurfaceView | |||
| SYSTEM_WINDOW | 2000~2999 | TYPE_STATUS_BAR | 2000 | 顶部的状态栏 | |
| TYPE_SEARCH_BAR | 2001 | 搜索窗口,系统中只能有一个搜索窗口 | |||
| TYPE_PHONE | 2002 | 电话窗口 | |||
| TYPE_SYSTEM_ALERT | 2003 | 警告窗口,在所有其他窗口之上显示 | 电量不足提醒窗口 | ||
| TYPE_KEYGUARD | 2004 | 锁屏界面 | |||
| TYPE_TOAST | 2005 | 短时的文字提醒小窗口 | |||
| TYPE_SYSTEM_OVERLAY | 2006 | 没有焦点的浮动窗口 | |||
| TYPE_PRIORITY_PHONE | 2007 | 紧急电话窗口,可以显示在屏保之上 | |||
| TYPE_SYSTEM_DIALOG | 2008 | 系统信息弹出窗口 | 比如SIM插上后弹出的运营商信息窗口 | ||
| TYPE_KEYGUARD_DIALOG | 2009 | 跟KeyGuard绑定的弹出对话框 | 锁屏时的滑动解锁窗口 | ||
| TYPE_SYSTEM_ERROR | 2010 | 系统错误提示窗口 | ANR 窗口 | ||
| TYPE_INPUT_METHOD | 2011 | 输入法窗口,会挤占当前应用的空间 | |||
| TYPE_INPUT_METHOD_DIALOG | 2012 | 弹出的输入法窗口,不会挤占当前应用窗口空间,在其之上显示 | |||
| TYPE_WALLPAPER | 2013 | 墙纸 | |||
| TYPE_STATUS_BAR_PANEL | 2014 | 从状态条下拉的窗口 | |||
| TYPE_SECURE_SYSTEM_OVERLAY | 2015 | 只有系统用户可以创建的OVERLAY窗口 | |||
| TYPE_DRAG | 2016 | 浮动的可拖动窗口 | 360安全卫士的浮动精灵 | ||
| TYPE_STATUS_BAR_PANEL | 2017 | ||||
| TYPE_POINTER | 2018 | 光标 | |||
| TYPE_NAVIGATION_BAR | 2019 | ||||
| TYPE_VOLUME_OVERLAY | 2020 | 音量调节窗口 | |||
| TYPE_BOOT_PROGRESS | 2021 | 启动进度,在所有窗口之上 | |||
| TYPE_HIDDEN_NAV_CONSUMER | 2022 | 隐藏的导航栏 | |||
| TYPE_DREAM | 2023 | 屏保动画 | |||
| TYPE_NAVIGATION_BAR_PANEL | 2024 | Navigation bar 弹出的窗口 | 比如说应用收集栏 | ||
| TYPE_UNIVERSAL_BACKGROUND | 2025 | ||||
| TYPE_DISPLAY_OVERLAY | 2026 | 用于模拟第二显示设备 | |||
| TYPE_MAGNIFICATION | 2027 | 用于放大局部 | |||
| TYPE_RECENTS_OVERLAY | 2028 | 当前应用窗口,多用户情况下只显示在用户节目 |
Android 浮窗开发之窗口层级的更多相关文章
- Android浮窗权限研究(转载)
这篇博客主要介绍的是 Android 主流各种机型和各种版本的悬浮窗权限适配,但是由于碎片化的问题,所以在适配方面也无法做到完全的主流机型适配,这个需要大家的一起努力,这个博客的名字永远都是一个将来时 ...
- Android 悬浮窗、悬浮球开发
原文:Android 悬浮窗.悬浮球开发 1.权限管理 直接看我另外一篇博客吧,传送门: https://my.oschina.net/u/1462828/blog/1933162 2.Base类Ba ...
- Android悬浮窗实现 使用WindowManager
Android悬浮窗实现 使用WindowManager WindowManager介绍 通过Context.getSystemService(Context.WINDOW_SERVICE)可以获得 ...
- 浮窗WindowManager view返回和Home按键事件监听
出于功能需求,需要在所有的view之上显示浮窗,于是需要在WindowManager的View上处理返回键的响应, mFloatingWindowView = layoutInflater.infla ...
- Android 使用WindowManager实现Android悬浮窗
WindowManager介绍 通过Context.getSystemService(Context.WINDOW_SERVICE)可以获得 WindowManager对象. 每一个WindowMan ...
- Android之NDK开发(转)
Android之NDK开发 一.NDK产生的背景 Android平台从诞生起,就已经支持C.C++开发.众所周知,Android的SDK基于Java实现,这意味着基于Android SDK进行开发的第 ...
- Android移动APP开发笔记——最新版Cordova 5.3.1(PhoneGap)搭建开发环境
引言 简单介绍一下Cordova的来历,Cordova的前身叫PhoneGap,自被Adobe收购后交由Apache管理,并将其核心功能开源改名为Cordova.它能让你使用HTML5轻松调用本地AP ...
- Android之NDK开发
转自:http://www.cnblogs.com/devinzhang/archive/2012/02/29/2373729.html 一.NDK产生的背景 Android平台从诞生起,就已经支持C ...
- 关于Android悬浮窗要获取按键响应的问题
要在Android中实现顶层的窗口弹出,一般都会用WindowsManager来实现,但是几乎所有的网站资源都是说弹出的悬浮窗不用接受任何按键响应. 而问题就是,我们有时候需要他响应按键,比如电视上的 ...
随机推荐
- 跨域之同源策略 Same-origin policy
同源策略是浏览器中最基本的隔离潜在恶意文件的安全策略,他限制了来自不同源(origin)的文档或脚本之间的相互作用. 何谓同源 在跨域之URL中介绍过一个URL的标准格式如下: 协议类型://服务器地 ...
- Python爬虫小白入门(一)写在前面
一.前言 你是不是在为想收集数据而不知道如何收集而着急? 你是不是在为想学习爬虫而找不到一个专门为小白写的教程而烦恼? Bingo! 你没有看错,这就是专门面向小白学习爬虫而写的!我会采用实例的方式, ...
- Android keycode列表
整理备忘! 基本按键 KEYCODE_0 按键'0' 7 KEYCODE_1 按键'1' 8 KEYCODE_2 按键'2' 9 KEYCODE_3 按键'3' 10 KEYCODE_4 按键'4' ...
- 利用Python进行数据分析(9) pandas基础: 汇总统计和计算
pandas 对象拥有一些常用的数学和统计方法. 例如,sum() 方法,进行列小计: sum() 方法传入 axis=1 指定为横向汇总,即行小计: idxmax() 获取最大值对应的索 ...
- 手把手教从零开始在GitHub上使用Hexo搭建博客教程(三)-使用Travis自动部署Hexo(1)
前言 前面两篇文章介绍了在github上使用hexo搭建博客的基本环境和hexo相关参数设置等. 基于目前,博客基本上是可以完美运行了. 但是,有一点是不太好,就是源码同步问题,如果在不同的电脑上写文 ...
- [C1] 分离 C1FlexGrid 滚动条
一 场景介绍 Silverlight 5.0 的 C1FlexGrid 控件里自带的滚动条,是嵌入在 C1FlexGrid 宽度和高度的范围里的,效果如下图所示: (未隐藏自带滚动条) (隐藏自带的 ...
- C# - 网络编程 之 Socket
命名空间 using System.Net; using System.Net.Socket; Socket类 初始化 public socket (AddressFamily addressFami ...
- PHP如何实现网址伪静态
Apache的 mod_rewrite是比较强大的,在进行网站建设时,可以通过这个模块来实现伪静态. 主要步骤如下: 1.检测Apache是否开启mod_rewrite功能 可以通过php提供 ...
- Servlet3.0的动态
动态的创建是为了简化配置文件的.对于我们创建的servlet,filter和listener后可以使用.这也是注解的另外一种替代方式. 动态的添加有两种,一种是基于ContextListener的,另 ...
- Matlab 之 find()函数
当我第一次用matlab语言编写一个工程项目时,发现自己编写的脚本里循环特别多,导致编程效率很低,这让我特别苦恼.有一次导师让我阅读他编写的一个Matlab脚本,并按照新要求对其进行更改.我发现脚本里 ...