深入理解View知识系列三-Window机制、Canvas的由来、Android事件的由来

我们在第一篇和第二篇中都涉及到了Window、WindowManager、PhoneWindow,而他们到底是什么,在第二篇又出现了WindowManagerImpl、WindowManagerGlobal、WindowSession、WindowManagerService,这么一堆的东西又都是干什么?起到什么样的作用?每个Activitiy都会存在一个Window,那么整个应用又一共有多少个Window?你听说过Surface吗?你知道Canvas是怎么来的吗?本篇就来详细的说说他们
本篇你会学到什么
  • 上面提到一堆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(String serviceName, Class<T> serviceClass,
ServiceFetcher<T> serviceFetcher)
{
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
//4.注册服务
registerService(Context.WINDOW_SERVICE, WindowManager.class,
new CachedServiceFetcher<WindowManager>() {
@Override
public WindowManager createService(ContextImpl ctx) {
return new WindowManagerImpl(ctx);
}});
WindowManagerImpl:

WindowManager的实现类,从上面注册服务的源码可以看出来,最终返回的是WindowManagerImpl,但是它并没有真正实现View的三大操作,全部桥接到了WindowMangerGloble

WindowManagerGloble :

真正实现View三大操作的类,它是一个单例类,它还管理着所有Window中的ViewRootImpl、DecorView、LayoutParams

ViewRootImpl :

整个View树的根,在WindowManagerGloble中的addView中被创建,是顶层DecorView的ViewParent,控制着整个View树的运作,包括measure、layout、draw、重绘、事件传递派发等

IWindowSession :

一个aidl接口,它的真的实现类是Session,它是一个Binder对象,用来和WindowManagerService建立连接,在ViewRootImpl的setView中最终也是通过它和WindowManagerService通信完成了Window的添加的。这个Session是应用唯一的,它的创建时在WindowManagerGloable中通过getWindowSession获取的

Session :

IWindowSession的真正实现类,这一点在WindowManagerGloble的获取中可以体现

//WindowManagerGloble
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
InputMethodManager imm = InputMethodManager.getInstance();
IWindowManager windowManager = getWindowManagerService();
//调用WMS的openSession
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值