Android开发艺术探索读书笔记 第八章 理解Window和WindowManager

Window是一个抽象类,具体实现是PhoneWindow。

8.1 Window和WindowManager

FLAG_NOT_FOCUSABLE
表示Window不需要获取焦点,也不需要接收各种输入事件,此标记会同时开启FLAG_NOT_TOUCH_MODAL
FLAG_NOT_TOUCH_MODAL
开启后可以将当期WWindow区域以外的事件传递给底层Window。
FLAG_SHOW_WHEN_LOCKED
开启此模式可以让Window显示在锁屏上
Type参数表示Window的类型,有三种,应用Window,子Window和系统Window。

应用Window对应一个Activity,子Window不能单独存在,要依附于父Window。

系统Window需要声明权限才能创建,如Toast和系统状态栏。

应用Window层级是1~99,子Window层级1000~1999,系统Window2000~2999。

ViewManager接口提供了添加、更新和删除View的三个方法。WIndowManager接口继承了ViewManager。

8.2 Window的内部机制

8.2.1 Window的添加过程

WindowManagerImpl的addView实际上是调用WindowManagerGlobal的addView。

1
2
3
4
5
6
7
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {

applyDefaultToken(params);
mGlobal.addView(view, params, mDisplay, mParentWindow);
}

而 mGlobal.addView创建了一个ViewRootImpl,然后通过ViewRootImpl的setView来更新界面。

setView内部通过requestLayout来完成异步刷新请求。最后通过WindowSession来完成最后的Window添加过程。添加是一次IPC调用。

Session内部通过WindowManagerService的addToDisplay方法实现Window的添加。

8.2.2 Window的删除过程

ViewRootImpl的die(boolean immediate)方法。

如果是异步的,将要删除的view放入mDyingViews中,然后发送一个MSG_DIE的消息。

同步的,就调用doDie方法,内部调用dispatchDetachedFromWindow();

主要工作是

1)垃圾回收,清楚数据和消息,移除回调。

2)通过Session的remove方法删除Window,同样是一个IPC过程,最终调用WMS的removeWindow。

3)调用View的dispatchDetachedFromWindow。

4)调用WindowManagerGlobal的doRemoveView方法刷新数据包。包括mRoots、mParams和mDyingViews,

需要将当期Window所关联的这三类对象从列表中删除。

8.2.3 Window的更新过程

首先更新view的LayoutParams,再更新viewRootImpl的LayoutParams,实现对View的重新测量,布局,重绘,最后通过WindowSession更新Window的视图,WindowManagerService.relayoutWindow()。

8.3 Window的创建过程

8.3.1 Activity的Window创建过程

Activity的启动过程最终会由ActivityThread的performLaunchActivity()来完成,方法内部通过类加载器创建Activity的实例。并调用attac方法为其管理运行过程中需要的上下文环境变量。

attach方法里,系统会创建Activity的mWindow,并且有activity实现window的接口。

Activity的顶级view是DecorView,本质上是FrameLayout。

Activity的setContentView的大致步骤:

  1. 如果没有DecorView,就创建一个。
  2. 将view添加到DecorView的mContentParent中。
  3. 回调Activity的onContentChanged方法同志Activity视图已经发生改变。

经过上面3个步骤,DecorView创建完成并初始化,,但没有被WindowManager添加到Window中。
在ActivityThread的handleResumeActivity方法中,会调用Activity的onResume,接着调用makeVisible(),在这里真正完成DecorView的添加和显示。

8.3.2 Dialog的Window创建过程

与Activity的创建过程基本一致。
普通的Dialog创建必须要用Activity的Context,如果用application的Context,会报错。因为没有token。token一般只有Activity的Context才有。
可以通过设置为系统级别对话框来,就能使用application的Context。
dialog.getWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)
需要声明权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

8.3.3 Toast的Window创建过程

Toast内部有两类IPC,一种是Tost访问NotificationManagerService,第二种是NMS回调TN接口。
Toast无法在没有Looper的线程中弹出,因为使用了handler将流程从binder线程池切换到当前线程。
非系统应用最多能同时存在50个ToastRecord,防止DOS。
NMS主要控制所有Toast显示的逻辑,但是具体显示工作任然交给调用者。

文章目录
  1. 1. 8.1 Window和WindowManager
  2. 2. 8.2 Window的内部机制
    1. 2.1. 8.2.1 Window的添加过程
    2. 2.2. 8.2.2 Window的删除过程
    3. 2.3. 8.2.3 Window的更新过程
  3. 3. 8.3 Window的创建过程
    1. 3.1. 8.3.1 Activity的Window创建过程
    2. 3.2. 8.3.2 Dialog的Window创建过程
    3. 3.3. 8.3.3 Toast的Window创建过程
,