window和windowManager
总阅读次
Window是一个窗口的概念,是一个抽象类,具体实现是PhoneWindow。
通过WindowManager来创建Window。
Window的具体实现位于WindowManagerService,WindowsManager和WindowMannagerService的交互是一个IPC的过程。
Window与WindowManager
(1). 使用WindowManager添加一个Window的过程:
|
|
上面的代码将一个Button添加到屏幕坐标为(100,300)的位置.
(2).WindowManager.LayoutParams中的flag参数表示Window的属性,下面是几个比较常用的属性。
- FLAG_NOT_FOCUSABLE
表示window不需要获取焦点,也不需要接收各种输入事件。此标记会同时启用FLAG_NOT_TOUCH_MODAL,最终事件会直接传递给下层的具有焦点的window;
- FLAG_NOT_TOUCH_MODAL:
在此模式下,系统会将window区域外的单击事件传递给底层的window,当前window区域内的单击事件则自己处理,一般都需要开启这个标记;
- FLAG_SHOW_WHEN_LOCKED
开启此模式可以让Window显示在锁屏的界面上
(3).TYPE参数表示Window的类型,有三种,分别是应用Window,子Window和系统Window。
应用window对应着一个Activity,子window不能独立存在,需要附属在特定的父window之上,比如Dialog就是子window。系统window是需要声明权限才能创建的window,比如Toast和系统状态栏这些都是系统window,需要声明的权限是。
(4). window是分层的,每个window都对应着z-ordered,层级大的会覆盖在层级小的上面,应用window的层级范围是1~99,子window的层级范围是1000~1999,系统window的层级范围是2000~2999。
[注意,应用window的层级范围并不是1~999哟]
(5).WindowManager继承自ViewManager,常用的只有三个方法:addView、updateView和removeView。
Window的内部机制
(1).Window是一个抽象的概念,不是实际存在的,它也是以View的形式存在。在实际使用中无法直接访问Window,只能通过WindowManager才能访问Window。每个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系。
(2). Window的添加、删除和更新过程都是IPC过程,以Window的添加为例,WindowManager的实现类对于addView、updateView和removeView方法都是委托给WindowManagerGlobal类,该类保存了很多数据列表,例如所有window对应的view集合mViews、所有window对应的ViewRootImpl的集合mRoots等,之后添加操作交给了ViewRootImpl来处理,接着会通过WindowSession来完成Window的添加过程,这个过程是一个IPC调用,因为最终是通过WindowManagerService来完成window的添加的。
Window的添加过程
(1)Activity的window创建过程
1.Activity的启动过程很复杂,最终会由ActivityThread中的performLaunchActivity来完成整个启动过程,在这个方法内部会通过类加载器创建Activity的实例对象,并调用它的attach方法为其关联运行过程中所依赖的一系列上下文环境变量;
2.Activity实现了Window的Callback接口,当window接收到外界的状态变化时就会回调Activity的方法,例如onAttachedToWindow、onDetachedFromWindow、dispatchTouchEvent等;
3.Activity的Window是由PolicyManager来创建的,它的真正实现是Policy类,它会新建一个PhoneWindow对象,Activity的setContentView的实现是由PhoneWindow来实现的;
4.Activity的顶级View是DecorView,它本质上是一个FrameLayout。如果没有DecorView,那么PhoneWindow会先创建一个DecorView,然后加载具体的布局文件并将view添加到DecorView的mContentParent中,最后就是回调Activity的onContentChanged通知Activity视图已经发生了变化;
5.还有一个步骤是让WindowManager能够识别DecorView,在ActivityThread调用handleResumeActivity方法时,首先会调用Activity的onResume方法,然后会调用makeVisible方法,这个方法中DecorView真正地完成了添加和显示过程。
|
|
(2)Dialog的Window创建过程
1.过程与Activity的Window创建过程类似,普通的Dialog的有一个特别之处,即它必须采用Activity的Context,如果采用Application的Context会报错。原因是Application没有应用token,应用token一般是Activity拥有的。
(3)Toast的Window创建过程
1.Toast属于系统Window,它内部的视图由两种方式指定:一种是系统默认的演示;另一种是通过setView方法来指定一个自定义的View。
2.Toast具有定时取消功能,所以系统采用了Handler。Toast的显示和隐藏是IPC过程,都需要NotificationManagerService来实现。在Toast和NMS进行IPC过程时,NMS会跨进程回调Toast中的TN类中的方法,TN类是一个Binder类,运行在Binder线程池中,所以需要通过Handler将其切换到当前发送Toast请求所在的线程,所以Toast无法在没有Looper的线程中弹出。
3.对于非系统应用来说,mToastQueue最多能同时存在50个ToastRecord,这样做是为了防止DOS(Denial of Service,拒绝服务)。因为如果某个应用弹出太多的Toast会导致其他应用没有机会弹出Toast。
Window的删除过程
(1)Window的删除过程和添加过程一样,都是先通过WindowManagerImpl后,再进一步通过WindowManagerGlobal来实现的。
(2)WindowManagerGlobal.java中的removeView方法:
|
|
(3)removeViewLocked是通过ViewRootImpl来完成删除操作的。在WindowManager中提供了两种删除接口removeView和removeViewImmediate,它们分别表示异步删除和同步删除,其中removeViewImmediate使用起来需要特别注意,一般来说不需要使用此方法来删除Window以免发生意外的错误。具体的删除操作由ViewRootImpl的die方法来完成。在die的内部会判断是异步删除还是同步删除。在异步删除的情况下,die方法只是发送了一个请求删除的消息后就立刻返回了,这个时候View并没有完成删除操作,所以最后会将其添加到mDyingViews中,mDyingViews表示待删除的View列表。
WindowManagerGlobal.java中的removeViewLocked方法:
|
|
(4)具体的删除操作由ViewRootImpl的die方法来完成。 在die的内部会判断是异步删除还是同步删除。在异步删除的情况下,die方法只是发送了一个请求删除的消息后就立刻返回了,这个时候View并没有完成删除操作。doDie内部会调用dispatchDetachedFromWindow方法,真正删除View的逻辑在dispatchDetachedFromWindow方法的内部实现。
ViewRootImpl.java中die方法:
|
|
(5)ViewRootImpl.java中doDie方法:
|
|
(5)doDie方法中调用的dispatchDetachedFromWindow是真正删除View的逻辑。
在doDie方法中调用,实现真正的删除View的逻辑。在这个方法中主要做四件事情:
(1)垃圾回收相关的工作,比如清除数据和消息、移除回调。
(2)通过Session的remove方法删除Window:mWindowSession.remove(mWindow),这同样是一个IPC过程, 最终会调用WindowManagerService的removeWindow方法。
(3)调用View的dispatchDetachedFromWindow方法:
* 在内部会调用View的onDetachedFromWindow()以及onDetachedFromWindowInternal()。
* 对于onDetachedFromWindow()大家一定不陌生,当View从Window中移除时,这个方法就会被调用,
* 可以在这个方法内部做一些资源回收的工作,
* 比如终止动画、停止线程等。
(4)调用WindowManagerGlobal的doRemoveView方法刷新数据,包括mRoots、mParams以及mDyingViews, 需要将当前Window所关联的这三类对象从列表中删除。
ViewRootImpl.java中dispatchDetachedFromWindow方法:
|
|
(7)整体的调用关系是:
ViewManager –>> WindowManager(继承自ViewManager) –>> WindowManagerImpl(继承自WindowManager) –>>WindowManagerGlobal(WindowManagerImpl内部的一个对象) –>> ViewRooImpl.die(ViewRooImpl是WindowManagerGlobal的removeView方法中的一个对象) –>> doDie(die中的一个方法调用,判断异步还是同步删除) –>> dispatchDetachedFromWindow(在doDie方法中调用,真正用于删除View的逻辑) –>> 通过Session的remove方法删除Window(IPC过程) –>> WindowManagerService.removeWindow –>> dispatchDetachedFromWindow(这个是子View的dispatchDetachedFromWindow方法) –>> onDetachedFromWindow和onDetachedFromWindowInternal(都是子View中的) –>> WindowManagerGlobal.doRemoveView
4、Window的更新过程
(1)从WindowManagerGlobal的updateViewLayout方法看起:
首先它需要更新View的LayoutParams并替换掉老的LayoutParams,接着再更新ViewRootImpl中的LayoutParams,这一步是通过ViewRootImpl的setLayoutParams方法来实现的。在ViewRootImpl中会通过scheduleTraversals方法来对View重新布局,包括测量、布局、重绘这三个过程。除了View本身的重绘以外,ViewRootImpl还会通过WindowSession来更新Window的视图,这个过程最终是由WindowManagerService的relayoutWindow()来具体实现的,它同样是一个IPC过程。
|
|
(2)整体的调用关系是:
ViewManager –>> WindowManager(继承自ViewManager) –>> WindowManagerImpl(继承自WindowManager) –>>WindowManagerGlobal(WindowManagerImpl内部的一个对象) –>> updateViewLayout(WindowManagerGlobal中的一个方法) –>> setLayoutParams(updateViewLayout方法中调用) –>> ViewRootImpl.setLayoutParams(ViewRootImpl是updateViewLayout中的一个对象) –>> scheduleTraversals方法(在setLayoutParams中调用,在ViewRootImpl中) –>> WindowSession(在ViewRootImpl中,是一个Binder) –>> WindowManagerService.relayoutWindow(具体实现,更新Window的视图,IPC)
未经许可不得转载,转载请注明zilianliuxue的blog,本人保留所有版权。