深入理解View知识系列三-Window机制Canvas的由来Android事件的由来
Posted 刘镓旗
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入理解View知识系列三-Window机制Canvas的由来Android事件的由来相关的知识,希望对你有一定的参考价值。
我们在第一篇和第二篇中都涉及到了Window、WindowManager、PhoneWindow,而他们到底是什么,在第二篇又出现了WindowManagerImpl、WindowManagerGlobal、WindowSession、WindowManagerService,这么一堆的东西又都是干什么?起到什么样的作用?每个Activitiy都会存在一个Window,那么整个应用又一共有多少个Window?你听说过Surface吗?你知道Canvas是怎么来的吗?本篇就来详细的说说他们
深入理解View知识系列一- setContentView和LayoutInflater源码原理分析
深入理解View知识系列二- View底层工作原理以及View的绘制流程
深入理解View知识系列三-Window机制、Canvas的由来、Android事件的由来
深入理解View知识系列四-View的测量规则以及三大方法流程
本篇你会学到什么
- 上面提到一堆Windowxxx都是干什么的
- Window的类型和级别
- Surface是干什么的
- View中的ondraw方法里的Canvas对象是哪来的?
- WMS添加Window的过程,和事件传递机制
同样的我们先来回顾一下上一篇的内容
Activity是在哪里准备显示View的
在setContentView之后,Activity会继续走它自己的生命周期方法,接着会走到ActivityThread中的handleResumeActivity中,在这个方法中会执行如下几部(只涉及View知识,其他的逻辑会在以后说)。
- 首先会执行performResumeActivity方法,在这里会回调Activity的onResume方法
- 接着会获取Activity的PhoneWindow和PhoneWindow中的DecorView,并把DecorView设置为INVISIBLE
- 然后获取在Activity中设置的WindowManager,并调用addView方法添加DecorView
- 最后调用Activity的makeVisible方法来将DecorView设置为VISIBLE
通过这几步我们还总结了两点
1.Activity是先回调了Activity的onResume之后才开始添加DecorView的,也就是说在oResume中是不能得到View的宽高参数的
2.Activity也是通过WindowManager来添加View的,这和我们平时自己使用WindowManger来添加一个View的流程类似。
WindowManger添加View的过程
WindowManger的是实现类是WindowManagerImpl,在WindowManagerImpl中包括addView在内操作View的三大方法全部使用了桥接到了WindowManagerGloble中,WindowManagerGloble是一个单例类,那么也就说明每个进程中所有对View的三大操作全部都只在这一个类中进行管理,在这里主要执行了如下几步。
- 检查传入参数的合法性
- 判断是否存在父Window,如果有会根据父Window调整一些信息参数
- 创建ViewRootImpl,并调用它的setView方法
- 将ViewRootImpl、LayoutParams、View添加进各自的集合中,这是因为WindowManagerGloble是一个单例类,无论存在多少个Window但是只存在一个WindowManagerGloble,所以要将这些东西存起来,以便于后面删除更新等操作。
ViewRootImpl的绘制开始点
在WindowManagerGloble中创建了ViewRootImpl,并调用了它的setView方法,逻辑转入到ViewRootImpl中,主要逻辑如下
- setView方法中主要通过requestLayout方法来准备开始View的绘制流程,通过WindowSession.addToDisplay完成Window添加的过程,还调用了View的assignParent方法来设置顶层View的Parent指向ViewRootImpl
- 在requestLayout的方法中先调用了checkThread来检查当前是否主线程
- 又调用了scheduleTraversals方法,在这里首先使用MessageQueue开启了一个同步消息屏障,这样就导致了主线程同步的消息将会暂停处理,目的是加快绘制的速度。
- 接着通过了Choreographer传递了一个Runnable,最终会执行Runnable中的run方法调用performTraversals来真正调用View的三大流程方法,即measure、layout、draw,
- 还有一些其他的知识点,例如为什么在onCreate中调用View.post方法就可以得到View的宽高、requestLayout请求重绘的过程等,详细的请看上一篇
开始之前我们先说一下一堆涉及Windowxxx的概念,本编源码基于android 7.1.1
Window :
顾名思义就是一个窗口,Android中所有的视图都需要通过Window来展示,它是一个抽象类,例如Activity、Toast、Dialog、PopupWindow等都必须通过Window才可以展示,它内部直接操作管理着View,可以说它是View的直接管理者,也可以说是相辅相成,互相依赖,谁离了谁都不行,而Window又分为三大类,这一点体现在WindowManager.LayoutParams中声明的常量中,这些常量用于type这个参数上,而且从声明中可以看出它们是分层级的,层级大的会覆盖在层级小的上面,如下
- 应用Window : 应用Window的层级对应于1-99,一般对应一个Activity
public static final int FIRST_APPLICATION_WINDOW = 1;
public static final int TYPE_BASE_APPLICATION = 1;
public static final int TYPE_APPLICATION = 2;
public static final int TYPE_APPLICATION_STARTING = 3;
public static final int TYPE_DRAWN_APPLICATION = 4;
public static final int LAST_APPLICATION_WINDOW = 99;
- 子Window : 子Window表示需要依赖于父Window才能存在的Window,它不能单独存在,例如Dialog、PopupWindow等,需要依赖Activity的应用Window才能存在。它的层级对应于1000-1999
public static final int FIRST_SUB_WINDOW = 1000;
public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;
public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;
public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;
public static final int TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4;
public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;
public static final int LAST_SUB_WINDOW = 1999;
- 系统Window : 系统Window是级别最高的Window,一般如果使用的话需要申请权限,例如Toast、输入法锁屏、系统警告、系统状态栏等都是系统Window,它的层级对应于2000-2999
public static final int FIRST_SYSTEM_WINDOW = 2000;
public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW;
public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1;
public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2;
public static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3;
public static final int TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4;
public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW+5;
....
public static final int LAST_SYSTEM_WINDOW = 2999;
如果没有设置type这个字段的值的话,默认是应用及Window,是TYPE_APPLICATION,这里从源码的WindowManager.LayoutParams的构造方法中可以看出来,
//LayoutParams的构造方法
public LayoutParams()
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
//默认值是2
type = TYPE_APPLICATION;
format = PixelFormat.OPAQUE;
PhoneWindow :
PhoneWindow是Window的唯一实现类,内部管理着最顶层的View,即DecorView
ViewManager :
一个接口,内部定义了操作View的三个方法,即addView、updateViewLayout、removeView
WindowManager:
也是一个接口继承了ViewManager,也是WindowManagerService代理包装类,这一点从context.getSystemService的源码中有体现,来看一下
//1.ContextImpl
@Override
public Object getSystemService(String name)
return SystemServiceRegistry.getSystemService(this, name);
//2.SystemServiceRegistry
public static Object getSystemService(ContextImpl ctx, String name)
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
//3.registerService
private static <T> void registerService深入理解View知识系列二- View底层工作原理以及View的绘制流程
深入理解View知识系列二- View底层工作原理以及View的绘制流程
Android View深入解析基础知识VelocityTracker,GestureDetector,Scroller