Android ViewRoot&DecorView&Window&Activity关系
DecorView介绍
Activity、View、Window的理解一篇文章就够了
Android - Activity 与 Window 与 View 之间的关系
Window
-
Window
表示一个窗口的概念, 是一个抽象类, 具体实现是PhoneWindow
. 每一个Window
都对应着一个View
和一个ViewRootImpl
.Window
和View
通过ViewRootImpl
来建立联系, 因此Window
并不是实际存在的, 它是以View
的形式存在. 这点可以从WindowManager
内定义的接口方法可以看出, 都是针对View
的, 这说明View
才是Window
存在的实体.Android
中所有的视图都是通过Window
来呈现的, 不管是Activity
,Dialog
还是Toast
, 它们的视图实际上都是附加在Window
上的. 因此也可以说Window
实际是View
的直接管理者.
WindowManager
-
WindowManager
是外界访问Window
的唯一入口, 并且可以通过WindowManager
来创建一个Window
,WindowManager
是一个接口, 它真正实现是WindowManagerImpl
, 但是又将内部的三大操作交给了WindowManagerGlobal
来处理. 所以最终就是调用WindowManagerGlobal.addView()
来创建.addView
的过程其实就是创建Window
的过程. 在addView
中 通过调用ViewRootImpl
来更新界面并完成Window
的添加. (其实最终Window
的添加请求是交给WindowManagerService
去处理了.WindowManagerService
内部会为每一个应用保留一个单独的Session
) -
WindowManager
和WindowManagerService
的交互是一个 IPC 的过程.
Activity 的 Window 创建过程
- 在
ActivityThread.performLaunchActivity()
方法中会调用Activity.attach(...)
方法为其关联运行过程中所依赖的一系列上下文环境变量. - 在
Activity.attach(...)
中, 系统会创建Activity
所属的Window
对象并为其设置回调接口,Window
对象的创建是通过PolicyManager
的makeNewWindow
方法实现的. - 由于
Activity
实现了Window
的Callback
接口, 因此当Window
接收到外界的状态改变时就会回调Activity
的方法.Callback
接口中的方法很多, 有几个是我们非常熟悉的, 例如:dispatchTouchEvent(), onAttachedToWindow(), onDetachedFromWindow()
等等.
getWindowManager().addView() 和 addContentView() 的区别
-
Activity
通过getWindowManager().addView()
,最终会调用到WindowManagerGlobal.addView()
,这时会创建一个新的ViewRootImpl
对象,和原来的DecoView
不在一条View
链上,所以它们之间的任何一个调用requestLayout()
都不会影响到另一个。而addContentView()
是直接将view
添加到DecoView
中,会使ViewRootImpl
链下的所有View
重绘。
Dialog 和 PopupWindow 的区别
-
Dialog
在创建时会新建一个Window(PhoneWindow)
,同时也会使用DecoView
作为这个PhoneWindow
的根View
,相当于走了一遍Activity
里创建PhoneWindow
和DecoView
的流程。而调用Dialog.show()
方法,类似于ActivityThread.performResumeActivity()
,将DecoView
添加到Window
,同时创建DecoView
链的RootViewImpl
来管理DecoView
。 -
PopupWindow
就和上面getWindowManager().addView()
类似了,只是创建一条新的View
链和ViewRootImpl
,并没有创建新的Window
。 - 而
Dialog
通过非Activity
的Context
,如Application
和Service
创建,这是因为Dialog
通过传入的Context
来得到context
里的mWindowManager
(也就是WindowManagerImpl
) 与mToken
,这是为了表明Dialog
所属的Activity
。在Window.addView()
时,需要这个mToken
(IBinder 对象),而Application
和Service
传入的情况下Token
是null
。
一个 Activity 有多少个 ViewRootImpl
- 每个
Activity
中ViewRootImpl
数量取决于调用mWindowManager.addView()
的次数。
摘自 Framework篇 - 一文搞懂 Activity、View、Window、ViewRootImpl