Window是一个抽象类,它的
体实现是PhoneWindow
,通过WIndowmanager来创建一个WIndow。WIndowManager是外界访问WIndow的入口
,Window具体实现是在WIndowManagerService中,而WindowManager和WindowMangerService的交互式一个IPC过程。Activity、Dialog和Toast是附加在WIndow上的,因此WIndow实际上是VIew的直接管理者。WindowManager添加一个Window的过程
//将一个Button添加到屏幕坐标为(100,300)的位置上
mFloatingButton = new Button(this);
mFloatingButton.setText("button");
mLayoutParams = new WindowManger.LayoutParams(
LayoutParams.WRAP_Content, LayoutParams.WRAP_CONTENT, 0, 0, PixelFormat.TRANSPARENT
);
mLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODEL|LayoutParams.FLAG_SHOW_WHEN_LOCKED|LayoutParams.FLAG_SHOW_WHEN_LOCKED;
mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
mLayoutParams.x = 100;
mLayoutParams.y = 300;
mWindowManger.addView(mFloatingButton, mLayoutParams);
Flags参数标识WIndow的属性:
FLAG_NOT_FOCUSABLE
:表示Window不需要获取焦点,也不需要接受各种输入事件,此标记会同时启用FLAG_NOT_TOUCH_MODEL,最终事件会直接传递给下层的具有焦点的WindowFLAG_NOT_TOUCH_MODAL
:在此模式下,系统会将当前Window区域以外的单击事件传递给底层的Window,当前Window区域以内的单击事件则自己处理。一般都需要开启此标记,否则其他Window将无法收到单击事件
FLAG_SHOW_WHEN_LOCKED
:开启此模式可以让Window显示在锁屏的界面上
Type参数表示Window的类型:
- 三种类型分别为应用Window、子Window和系统Window。
- 子Window不能单独存在,它需要附属在特定的父Window中(
Dialog
)。系统Window是需要声明去权限才能创建Window(Toast
和状态栏
) - Window是分层的,每个Window都有对应的z-ordered。层级大的会覆盖在层级小的Window的上面。而应用Window的层级范围是1~99,子Window的层级范围是1000~1999,系统Window的层级范围是2000~2999,这些层级范围对应着Windowmanager.LayoutParams的type参数
- WindowManager提供了三个方法:添加View/更新View和删除View
Windiw的内部机制
在实际使用中无法直接访问WIndiw,对Window的访问必须通过WindowManager。
- WIndow的添加过程
Window的添加过程实现添加过程的是WindowManagerImpl
类,但它也没有直接实现WIndow的三大操作,而是全部交给了WIndowManagerGlobal
来处理。添加过程最终由ViewRootImpl的setView方法完成,之后setView内部会通过requestLayout来完成一部数显请求,之后调用WindowSession
来完成Window的添加过程。Window的添加过程是一次IPC调用
- Window的删除过程
有两种删除方式异步删除和同步删除。真正删除View的逻辑是在doDie方法内部会调用dispatchDetachedFromWindow
方法的内部实现。 - WIndow的更新过程
会调用updateViewlayout方法,在ViewRootImpl中会通过scheduleTraversals方法来对View重新布局,包括测量、布局和重绘三个过程、它同样是一个IPC过程
Window的创建过程
- Activity的WIndow的创建过程
Activity将具体实现交给了Window处理,而Window的具体实现时PhoneWIndow.
- DecorView的创建工行才能有installDector方法来实现,在方法内部会通过generateDecor方法来直接创建DecorVIew,之后PhoneWindow需要通过
generateLayout方法
来加载具体的布局文件到DecorView中。 - 初始完成了DecorView之后,将Activity的布局文件添加到DecorView里面,在这里Activity的布局文件只是被添加到DecorView的mContentParent中
- 之后回调Activity的onContentChanged方法通知Activity视图发生改变
- 最后一步,在ActivityThread的handleResumeActivity方法中,调用Activity的onResume方法,接着会
调用Activity的makeVisible()
,也正是在makeVisible方法中,DecorView真正完成了添加和显示着两个过程。
- DecorView的创建工行才能有installDector方法来实现,在方法内部会通过generateDecor方法来直接创建DecorVIew,之后PhoneWindow需要通过
- Dialog的Window创建过程
- 过程与Activity的Window创建过程类似,普通的Dialog的有一个特别之处,
即它必须采用Activity的Context
,如果采用Application的Context会报错。原因是Application没有应用token,应用token一般是Activity拥有的。[service貌似也有token?]
- 过程与Activity的Window创建过程类似,普通的Dialog的有一个特别之处,
- Toast的Window创建过程
- Toast是基于Window来实现的,但是由于Toast具有定时取消这一功能吗,所以系统刚才用了Handler。其中有两类IPC过程,一类是Toast访问
NotificationManagerService
,第二类是NotificationManagerService回调Toast里的TN接口。 - Toast属于系统Window,内部的视图由两种方式指定,一种是系统默认的样式,另一种是通过setView方法来指定一个自定义View.
- 显示和隐藏都需要通过NMS来实现,而它都是通过远程调用的方式来显示和隐藏Toast,这里要用到Handler将其切换到当前线程,所以Toast无法再没有Looper的线程中弹出。
- 在NMS的enqueToast方法中,将Toast请求封装为ToastRecord对象并将其添加到一个名为mToastQueue的队列中。最多同时存在50个ToastRecoed.
- 显示和隐藏都是一次IPC过程
- Toast是基于Window来实现的,但是由于Toast具有定时取消这一功能吗,所以系统刚才用了Handler。其中有两类IPC过程,一类是Toast访问