开发艺术探索-- Window及WindowManager

第八章,理解Window及WindowManager

Window及WindowManager
Window内部机制
Window创建过程

  1. Window是一个抽象类,实现类是PhoneWindow, 创建Window只需要通过WindowManager
  2. Window的具体实现在WindowManagerService中,WindowManagerWindowManagerService是一个IPC过程
  3. WindowView的直接管理者

Window及WindowManager

通过WindowManager.addView方法即可将View添加到Window,

mLayoutParams = new WindowManager.LayoutParams(
                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0,
                    PixelFormat.TRANSPARENT);
                    //Window的属性
            mLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL//一般需要开启
                    | LayoutParams.FLAG_NOT_FOCUSABLE//Window不需要获取焦点,不需要各种输入事件,需要同时开启FLAG_NOT_TOUCH_MODAL,使事件下传.
                    | LayoutParams.FLAG_SHOW_WHEN_LOCKED;//让window显示在锁屏上
                    //window的类型,应用widow,子window,系统window
            mLayoutParams.type = LayoutParams.TYPE_SYSTEM_ERROR;
            mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
            mLayoutParams.x = 100;
            mLayoutParams.y = 300;//显示位置
            mWindowManager.addView(mFloatingButton, mLayoutParams);

Window层级,z-ordered.层级大的会覆盖在小的上面.对应着mLayoutParams.type参数
应用window: 1~99
子window: 1000~1999
系统window: 2000~2999

WindowManager功能只有三个方法,即添加View,更新View,删除View,
WindowManager继承了ViewManager,操作Window的过程更像是操作Window中的View.

Window内部机制

Window是一个抽象概念,每个Window对应着一个View和一个ViewRootImpl

           ViewRootImpl
Window  <-----------------> View

Window并不是实际存在的,它是以View的形式存在的.View才是Window存在的实体

Window的添加过程

//桥接模式
WindowManagerImpl#addView --> WindowManagerGlobal#addView

WindowManagerGlobal添加过程:

  1. 检查参数是否合法
  2. 创建ViewRoorImpl将View添加到列表中.
  3. 通过ViewRoorImpl更新界面(调用requestLayout)
ViewRootImpl -> Session(WindowSession的实现类) 
-> WindowManagerService#addWindow

Window的删除过程

WindowManagerImpl#removeView -> WindowManagerGlobal#removeView 
-> findViewLocked -> removeViewLocked 
-> ViewRootImpl#die -> dispatchDetachedFromWindow
  1. 通过findViewLocked查找待删除的View的索引.
  2. removeViewLocked调用ViewRootImpl的删除方法来做进一步的删除.
  3. removeViewremoveViewImmediate,分别代表异步和同步删除

ViewRootImpl#die中做了判断,如果是同步删除,则调用doDie
如果是异步删除,就发送一个MSG_DIE,ViewRootImpl#Handler会处理此消息并调用doDie.

dispatchDetachedFromWindow所做的工作
1. 垃圾回收相关的工作
2. 通过Session#remove删除Window,IPC操作WindowManagerService#removeWindow
3. 调用 View#onDetachedFromWindow,终止动画,停止线程
4. 调用WindowManagerGlobal#doRemoveView刷新数据.

Window的更新过程

依然是调用WindowManagerGlobal#updateViewLayout.

  1. 更新View的LayoutParams,并替换掉老的LayoutParams.
  2. 通过ViewRootImpl#setLayoutParams更新ViewRootImpl的LayoutParams
  3. ViewRootImpl#scheduleTraversals重新测量,布局,绘制

Window创建过程

  1. view不能单独存在,必须附着在window之上,有视图的地方就有widow.
  2. Android中可提供视图的地方有Activity,Dialog,Toast,PopUpWindow,菜单.

Activity的Window创建过程

  1. Activity的启动过程最终由ActivityThread#performLaunchActivity完成.
    方法内部会通过类加载器加载Activity的实例.并调用attach方法关联运行过程中上下文环境.
  2. attach方法中会调用PolicyManager#makeNewWindow创建window对象,并设置回调接口.
  3. Activity实现了Window.CallBack,因此,当状态改变时会回调Activity.
  4. PolicyManager是一个策略类,方法都在IPolicy接口中声明了.真正实现类是Policy
  5. PolicyManagerPolicy的关联,可能是在编译环节动态控制的.
  6. 通过Activity#setContentView将视图附着到window上
  1. 如果没有DecorView,就创建它
  2. View添加到DecorView.mContentParent
  3. 回调Activity#onContentChanged

经过上面的步骤,DecorView并没有添加到Window,Activity还无法接受输入事件,具体加入步骤如下:

Activity#attach -> PolicyManager#makeNewWindow 
-> Activity#setContentView  -> ActivityThread#handleResumeActivity -> Activity#onResume 
-> Activity#makeVisible -> mWindowManager.addView//添加DecorView

Dialog的Window创建过程

  1. 创建Window,依然是PolicyManager#makeNewWindow
  2. 初始化DecorView,并将Dialog视图添加到DecorView
  3. DecorView添加到Window中并显示
  4. Dialog关闭,则通过windowManager#removeViewImmediate(mDecor)移除.

注意: 普通Dialog必须采用ActivityWindow

Toast的Window创建过程

  1. Toast的工作过程比Dialog稍显复杂,Toast具有定时取消这一功能(采用Handler).
  2. Toast内部有两类IPC过程.一类,Toast->NotificationManagerService,二类,NotificationManagerService -> Toast#TN
  3. Toast属于系统Window,内部视图可以通过setView来指定
  4. Toast提供show和cancel方法,他们是一个IPC过程,都是通过NMS完成
  5. TN是一个Binder类,NMS回调TN来处理Toast的show和cancel
  6. 由于TN运行在Binder线程池中,因此需要使用Handler(必须在有Looper的线程中弹出Toast)
  7. LONG_DELAY = 3.5s,SHORT_DELAY = 2s,延迟消息发送后就会通过cancelToastLocked来隐藏Toast,并从mToastQueue中移除.
// 将Toast封装为ToastRecord添加到mToastQueue中
Toast#show -> NMS#enqueueToast -> mToastQueue#add(ToastRecord)
// mToastQueue对于非系统应用,最多同时50个ToastRecord,防止DOS
-> NMS#showNextToastLocked ->toastRecord.callBack#show
// 这里callback就是Toast#TN对象的远程Binder,最终回调TN中的方法运行在发起Toast的线程池中.

//显示后,延时关闭
scheduleTimeoutLocked(ToastRecord)->sendMessageDelayed 
-> toastRecord.callBack#hide -> mHandler.post(mShow) 
-> TN#handleHide -> mWm.removeView
//这里 callback 就是 Toast#TN 的远程Binder,运行在Binder线程池中,需要用Handler切换线程,最终通过 TN#handleHide 调用 WindowManager 移除 View

扩展阅读
浅析Android的窗口

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值