Window | 层级 |
---|---|
应用 Window | 1~99 |
子 Window | 1000~1999 |
系统 Window | 2000~2999 |
WindowManagerService 添加一个窗口的过程,其实就是 WindowManagerService 为其分配一块 Surface 的过程,一块块的 Surface 在 WindowManagerService 的管理下有序的排列在屏幕上,Android 才得以呈现出多姿多彩的界面。
WindowManagerService 就是位于 Framework 层的窗口管理服务,它的职责就是管理系统中的所有窗口。
Window 有三种类型,分别是应用 Window、子 Window 和系统 Window。应用类 Window 对应一个 Acitivity,子 Window 不能单独存在,需要依附在特定的父 Window 中,比如常见的一些 Dialog 就是一个子 Window。系统 Window是需要声明权限才能创建的 Window,比如 Toast 和系统状态栏都是系统 Window。
Window | 层级 |
---|---|
应用 Window | 1~99 |
子 Window | 1000~1999 |
系统 Window | 2000~2999 |
WindowManager 使用
我们对 Window 的操作是通过 WindowManager 来完成的,WindowManager 是一个接口,它继承自只有三个方法的 ViewManager 接口:
public interface ViewManager{
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
这三个方法其实就是 WindowManager 对外提供的主要功能,即添加 View、更新 View 和删除 View。
如果要设置为系统 Window,应该添加权限:
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
0, 0,
PixelFormat.TRANSPARENT
);
// flag 设置 Window 属性
layoutParams.flags= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
// type 设置 Window 类别(层级)
layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
layoutParams.gravity = Gravity.CENTER;
WindowManager windowManager = getWindowManager();
windowManager.addView(floatingButton, layoutParams);
终于,Window 的添加请求移交给 WindowManagerService 手上了,在 WindowManagerService 内部会为每一个应用保留一个单独的 Session,具体 Window 在 WindowManagerService 内部是怎么添加的,就不对其进一步的分析.
与WMS建立Session之后就调用ViewRootImpl的setView方法,
setView很复杂,我们关注两步:
- requestLayout
- 向WMS发起显示当前Window的请求
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();//发送DO_TRAVERSAL消息
}
}
就是往Handler中发送一个DO_TRAVERSAL消息,这个消息会触发整个视图树的绘制操作,最终会执行performTraversals函数,在performDraw中,framework会获取到图形绘制表面Surface对象,通过mSurface.lockCanvas获取canvas.
视图树绘制流程:
- 判断是CUP还是GPU绘制.
- 获取绘制表面Surface对象.
- 通过Surface对象获取并锁住Canvas绘图对象.
- 从DecorView开始发起整颗视图树的绘制流程.
- Surface对象解锁Canvas,并且通知SurfaceFlinger更新视图.
Window 的创建过程
View 是 Android 中的视图的呈现方式,但是 View 不能单独存在,它必须附着在 Window 这个抽象的概念上面,因此有视图的地方就有 Window.
Activity、Dialog、Toast 等视图都对应着一个 Window.
Activity 的 Window 创建就发生在 attach 方法里
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
...
public Window makeNewWindow(Context context){
return new PhoneWindow(context);
}
Window 的具体实现类的确是 PhoneWindow。到这里 Window 以及创建完成了.
Activity 的视图是怎么附属到 Window 上的?从 setContentView 入手.
PhoneWindow 的相关逻辑即可,它的处理步骤如下:
- 如果没有 DecorView 就创建一个
DecorView 是 Activity 中的顶级 View,是一个 *FrameLayout,一般来说它的内部包含标题栏和内容栏,但是这个会随着主题的变化而改变,不管怎么样,内容栏是一定存在的,并且有固定的 id:”android.R.id.content”,在 PhoneWindow 中,通过 generateDecor 方法创建 DecorView,通过 generateLayout 初始化主题有关布局。
- 将 View 添加到 DecorView 的 mContentParent 中
这一步较为简单,直接将 Activity 的视图添加到 DecorView 的 mContentParent 中即可,由此可以理解 Activity 的 setContentView 这个方法的来历了,为什么不叫 setView 呢?因为 Activity 的布局文件只是被添加到 DecorView 的 mContentParent 中,因此叫 setContentView 更加具体准确。
- 回调 Activity 的 onContentChanged 方法通知 Activity 视图已经发生改变
前面分析到 Activity 实现了 Window 的 Callback 接口,这里当 Activity 的视图已经被添加到 DecorView 的 mContentParent 中了,需要通知 Activity,使其方便做相关的处理。
DecorView 已经被创建并初始化完毕,Activity 的布局文件也已经成功添加到了 DecorView 的 mContentParent 中,但是这个时候 DecorView 还没有被 WindowManager 正式添加到 Window 中。
在Acitivy 的 onResume 方法中,接着会调用 Acitivy 的 makeVisible() 方法,正是在 makeVisible 方法中,DecorView 才真正的完成了显示过程,到这里 Activity 的视图才能被用户看到,如下:
void makeVisible(){
if(!mWindowAdded){
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
任何 View 都是附属在一个 Window 上面的,Window 表示一个窗口的概念,也是一个抽象的概念,Window 并不是实际存在的,它是以 View 的形式存在的。WindowManager 是外界也就是我们访问 Window 的入口,Window 的具体实现位于 WindowManagerService 中,WindowManagerService 和 WindowManager 的交互是一个 IPC 过程。