理解Window和WindowManager
Window表示一个窗口的概念,Window是一个抽象类,它的具体实现是PhoneWindow。创建一个Window,需要通过WindowManager即可完成,WindowManager是外界访问Window的入口,Window具体实现位于WindowManagerService中,WindowManager和WindowManagerService的交互是一个IPC的过程。Android中,所有的视图都是通过Window来呈现,不管是Activity、Dialog、还是Toast,它们的视图实际上都是附加在Window上,因此Window是实际View的直接管理者,单击事件由Window传递给DecorView,然后再由DecorView传递给我们的View,就连Activity的设置视图方法setContentView在底层也是通过Window来完成的。
Window和WindowManager
添加一个Window的过程,重点代码是:
mWindowManager.addView(mFLoatingButton,mLayoutParams);
WindowManager.LayoutParams中有两个flags和type参数。
Flags参数有三个Window属性
- FLAG_NOT_FOCUSABLE。表示Window不需要获取焦点,也不需要接收各种输入事件,最终事件会直接传递给下层的具有焦点的Window
- FLAG_NOT_TOUCH_MODAL。在此模式下,系统会将当前Window区域以外的单击事件传递给底层的Window,当前Window区域以内的单击事件则自己处理,这个标记很重要,一般来说都需要开启此标记,否则其他Window将无法收到单击事件
- FLAG_SHOW_WHEN_LOCKED。开启此模式可以让Window显示在锁屏的界面上。
Type参数表示Window的类型,有三种类型,分别是应用Window,子Window和系统Window,应用类Window对应一个Activity,子Window不能单独存在,它需要附属在特定的父Window之中,比如常见的Dialog就是一个子Window,系统Window是需要声明权限在能创建的Window,比如Toast和系统状态栏这些都是系统Window。
Window是分层的,每个Window都有对应的z-ordered,层级大的会覆盖在层级小的Window的上面,在三类Window中,应用类的Window的层级范围是1-99,子Window的层级范围是1000-1999,系统Window的层级的范围是2000-2999,这些层级范围对应着WindowManager.LayoutParams的Type参数。如想要Window位于所有Window的最顶层,那么采用较大的层级即可。很显然系统Window层级是最大的,而且系统层级有很多值。
WindowManager所提供的功能很简单,常用有三个方法,即添加View,更新View和删除View,这三个方法定义在ViewManager中,而WindowManager继承了ViewManager。
Window的内部机制
Window是一个抽象的概念,每一个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系,说明View才是Window存在的实体,在实际使用中无法直接访问Window,对Window的访问必须通过WindowManager。
Window的添加过程
Window的添加过程需要通过WindowManager的addView来实现,WindowManager是一个接口,它的真正实现是WindowManagerImpl类。
@Override
public void addView(View view,ViewGroup.LayoutParams params){
mGlobal.addView(view,params,mDisplay,mParentWindow);
}
@Override
public void updateViewLayout(View view,ViewGroup.LayoutParams params){
mGlobal.updateViewLayout(view,params);
}
@Override
public void removeView(View view){
mGlobal.removeView(view,false);
}
可以看到,WindowManagerImpl并没有直接实现Window的三大操作,而是全部交给了WindowManagerGlobal来处理,WindowManagerGlobal以工厂的形式向外提供自己的实例。WindowManagerGlobal的addView方法主要分为如下几步:
- 检查参数是否合法,如果是子Window那么还需要调整一些布局参数
- 创建ViewRootImpl并将View添加到列表中
- 通过ViewRootImpl来更新界面并完成Window的添加过程
Window的删除过程
Window的删除过程和添加过程一样,都是先通过WindowManagerImpl后,在进一步通WindowManagerGlobal来实现的。里面用到一个dispatchDetachedFromWindow方法内部实现,这个方法主要做了四件事:
- 垃圾回收相关的工作,比如清除数据和消息、移除回调
- 通过Session的remove方法删除Window
- 调用View的dispatchDetachedFromWindow方法,在内部会调用View的onDetachedFromWindow()以及onDetachedFromWindowInternal()
- 调用WindowManagerGlobal的doRemoveView方法刷新数据
Window的更新过程
主要是用到updateViewLayout方法,首先它需要更新View的LayoutParams并替换掉老的LayoutParams,接着再更新ViewRootImpl中的LayoutParams,这一步是通过ViewRootImpl的setLayoutParams方法来实现的。在ViewRootImpl中会通过scheduleTraversals方法对View进行重新布局,包括测量、布局、重绘这三个过程。
Window的创建过程
View是Android中的视图呈现方式,但是View不能单独存在,它必须附着在Window这个抽象的概念上面,因此有视图的地方就有Window。
Activity的Window创建过程
如何创建,需要了解Activity启动过程,比较复杂,但它最终由ActivityThred中的perfromLaunchActivity()来完成整个启动过程,在这个方法内部会通过类加载器创建Activity的实例对象,并调用其attach方法为其关联运行过程中所依赖的一系列上下文环境变量。
在Activity的attach方法里,系统会创建Activity所属的Window对象并为其设置回调接口,Window对象的创建是通过PolicyManager的makeNewWindow方法实现的,对于Activity的setContentView的实现可以看出,Activity将具体实现交给了Window处理,而Window的具体实现是PhoneWindow,所以只需要看PhoneWindow相关逻辑即可,大致以下几个步骤:
- 如果没有DecorView,那么就创建它。DecorView是一个FrameLayout,是Activity的顶级View,一般来说它的内部包含标题栏和内部栏。
- 将View添加到DecorView的mContentParent中。
- 回调Activity的onContentChanged方法通知Activity视图已经发生改变。Activity的onContentChanged是一个空实现。
经过上面三个步骤,DecorView已经被创建初始化完毕,Activity的布局文件已经成功添加到了DecorView的mContentParent中,但是这个时候DecorView还没有被WindowManager正式添加到Window中,真正被视图调用是在Activity的onResume方法,接着会调用Activity的makeVisible(),正是在makeVisible方法中,DecorView真正地完成了添加和显示这两个过程。
Dialog的Window创建过程
Dialog的Window的创建过程和Activity类似,有以下几个步骤:
- 创建Window。同样是通过PolicyManager的makeNewWindow方法来完成的。
- 初始化DecorView并将Dialog的视图添加到DecorView中。
- 将DecorView添加到Window中并显示。在Dialog的show方法中,会通过WindowManager将DecorView添加到Window中。
普通的Dialog有一个特殊之处,那就是必须采用Activity的Context,如果采用Application的Context,就会报错。
Toast的Window创建过程
Toast和Dialog不同,它的工作过程稍微复杂。首先Toast也是基于Window来实现的,但是由于Toast具有定时取消这一功能,所以系统采用了Handler。在Toast的内部有两类的IPC过程,第一类是Toast访问NotificationManagerService,第二类是NotificationManagerService回调Toast的TN接口。
Toast属于系统Window,它内部的视图有两种方式指定,一种是系统默认的样式,另一种是通过setView方法来指定一个自定义View,不管如何,它们都对应Toast的一个View类型的内部成员mNextView。Toast提供了show和cancel分别用于显示和隐藏Toast,它们的内部是一个IPC过程。
阅读扩展
源于对掌握的Android开发基础点进行整理,罗列下已经总结的文章,从中可以看到技术积累的过程。
1,Android系统简介
2,ProGuard代码混淆
3,讲讲Handler+Looper+MessageQueue关系
4,Android图片加载库理解
5,谈谈Android运行时权限理解
6,EventBus初理解
7,Android 常见工具类
8,对于Fragment的一些理解
9,Android 四大组件之 " Activity "
10,Android 四大组件之" Service "
11,Android 四大组件之“ BroadcastReceiver "
12,Android 四大组件之" ContentProvider "
13,讲讲 Android 事件拦截机制
14,Android 动画的理解
15,Android 生命周期和启动模式
16,Android IPC 机制
17,View 的事件体系
18,View 的工作原理
19,理解 Window 和 WindowManager
20,Activity 启动过程分析
21,Service 启动过程分析
22,Android 性能优化
23,Android 消息机制
24,Android Bitmap相关
25,Android 线程和线程池
26,Android 中的 Drawable 和动画
27,RecylerView 中的装饰者模式
28,Android 触摸事件机制
29,Android 事件机制应用
30,Cordova 框架的一些理解
31,有关 Android 插件化思考
32,开发人员必备技能——单元测试
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
2016-02-04 谈谈Android 6.0运行时权限理解
2015-02-04 Android 四大组件之 " Activity "