Android 窗口管理、View绘制、事件分发(草稿)

一、从哪开始说起呢?问:屏幕上可见的各种窗口和视图是谁在统一管理?

Android的窗口视图统一由 android.view.WindowManagerGlobal 管理(单例类),对应到它的mRoots和mViews 属性上。


ViewRootImpl:视图层次结构的顶部(顶级视图),实现了视图和窗口管理器之间所需的协议。

何时创建并关联到WindowManagerGlobal

mViews是扁平化的管理每次添加的view,而mRoots是以视图层级的形式管理每次添加的view。


上图第3步:ViewRootImpl.setView()会触发什么消息和功能?

下图3、4步和输入事件有关,作为一个独立方向研究:


谁会去调用WindowManagerGlobal的addView()呢?


 谁创建WindowManagerImpl并用到其addView()方法?

虚拟的窗口概念对于一个抽象类Window,

通过 setWindowManager 创建并关联 WindowManagerImpl实例。

传入的wm都是通过系统服务拿到的

  

createPresentationWindowManager只用于一种特殊的对话框:Presentation extends Dialog


哪些使用WindowManagerImpl的地方?有哪些Window?


Activity和Dialog都依赖PhoneWindow,PhoneWindow是怎么使用WindowManager的?


其他的视图如:Toast、悬浮窗、DialogFragment、PopupWindow等,是怎么使用WindowManagerImpl的

Toast

 

 

PopupWindow


测试验证结果:

Toast、Activity、Dialog、PopupWindow分别是独立的view树。

DialogFragment 作为嵌入式View使用时,没有独立的view树,作为弹窗使用时,有对应的Dialog的PhoneWindow的view树。

 

向前追溯告一段落,下面从WindowManagerService的addWindow开始。


 

以上可以看出:ViewRootImpl的setView 到 Session的addToDisplay是跨进程调用。


WMS的创建,并且是个单例,

 

 

 WMS有哪些重要的成员:


    /** WMP是窗口管理策略的接口类,具体实现类是:PhoneWindowManager */
    @VisibleForTesting
    WindowManagerPolicy mPolicy;
    
    /**
     * 与客户端的所有当前活动会话。(每一个应用程序进程都会对应一个Session)
     */
    final ArraySet<Session> mSessions = new ArraySet<>();

    /** 从IWindow IBinder映射到服务器的Window对象。
      * mWindowMap 是key值为IBinder, value为WindowState的HashMap 
      * mWindowMap 用来保存WMS中各种窗口的集合
      */
    final WindowHashMap mWindowMap = new WindowHashMap();

    /**
     * 等待替换窗口的应用程序窗口令牌列表。
     * 如果更换不及时,陈旧的窗户就需要处理掉。
     */
    final ArrayList<AppWindowToken> mWindowReplacementTimeouts = new ArrayList<>();


    /** 正在调整大小的窗口, 这样我们就可以在完成调整底层表面大小的事务后告诉客户端调整大小的情况 */
    final ArrayList<WindowState> mResizingWindows = new ArrayList<>();

    /** 动画已经结束,现在必须删除的窗口。*/
    final ArrayList<WindowState> mPendingRemove = new ArrayList<>();

    /**
     * 在处理mPendingRemove时使用,以避免处理原始数组。
     */
    WindowState[] mPendingRemoveTmp = new WindowState[20];


    /** 表面应该被销毁的窗户。*/
    final ArrayList<WindowState> mDestroySurface = new ArrayList<>();

    /**
     * surface未被destroy的窗户。这些窗户的surface正在发生变化。我们保留旧surface,直到新 
     * surface上的第一帧完成绘制。     
     */
    final ArrayList<WindowState> mDestroyPreservedSurface = new ArrayList<>();

    /** 这是在内存耗尽时设置的,它将是一个空列表或包含需要强制删除的窗口。*/
    final ArrayList<WindowState> mForceRemoves = new ArrayList<>();

    /** 客户端等待绘制的窗口。*/
    ArrayList<WindowState> mWaitingForDrawn = new ArrayList<>();

    /** 当前导致隐藏非系统覆盖窗口的窗口列表。 */
    private ArrayList<WindowState> mHidingNonSystemOverlayWindows = new ArrayList<>();

    /** 系统的Handler, 用于将任务加入到主线程消息队列中,这样代码逻辑就会在主线程中执行 */
    final H mH = new H();

    PowerManager mPowerManager;
    PowerManagerInternal mPowerManagerInternal;
    
    /** IMS会对触摸事件进行处理,会寻找一个最合适的窗口来处理触摸反馈信息,WMS是窗口的管理者,隐藏作为输入系统的中转站在合适不过 */
    final InputManagerService mInputManager;
    final DisplayManagerInternal mDisplayManagerInternal;
    final DisplayManager mDisplayManager;
    final ActivityTaskManagerService mAtmService;

    /** 管理窗口的动画以及特效动画
    final WindowAnimator mAnimator;
    final SurfaceAnimationRunner mSurfaceAnimationRunner;

    /**
     * 跟踪哪个动画被转移到哪个animators。当动画结束时,条目将被清理。
     */
    final ArrayMap<AnimationAdapter, SurfaceAnimator> mAnimationTransferMap = new ArrayMap<>();

1260行:attrs.token 是IBinder类型的对象,windowForClientLocked方法内部会根据 attrs.token作为key值从mWindowMap中获取该子窗口的父窗口。

 

 

 WindowToken是什么?

窗口管理器中一组相关窗口的容器。

通常这是一个AppWindowToken,它是一个Activity的句柄,它用来显示窗口。

对于嵌套窗口,为父窗口创建了一个WindowToken来管理其子窗口。 

DisplayContent是什么?

用于跟踪窗口状态和特定Display的其他相关内容的实用工具类。

WindowContainer

定义类的通用功能,该类可以直接或通过其子类以层次结构形式保存窗口。

WindowState是什么?

窗口管理器中的窗口。

Display:

提供有关逻辑显示器的大小和密度的信息。
显示区域用两种不同的方式描述:

1. 应用程序显示区域指定显示的部分可能包含应用程序窗口,不包括系统装饰。

(应用程序显示区域可能比实际显示区域小,因为系统减去了装饰元素(如状态栏)所需的空间。可以通过以下方法查询应用显示区:{@link #getSize}、{@link #getRectSize}和{@link #getMetrics}。)

2. 实际显示区域指定显示的部分,其中包含系统装饰等内容。

(即使如此,如果窗口管理器使用(adb shell wm size)模拟一个更小的显示,实际显示区域可能比显示的物理大小更小。查询真实显示区域的方法如下:{@link #getRealSize}, {@link #getRealMetrics}。)

逻辑显示并不一定代表特定的物理显示设备,如内置屏幕或外部监视器。根据当前连接的设备以及是否启用了镜像,逻辑显示的内容可以显示在一个或多个物理显示上。

 

 


总结一下:

1. 屏幕显示的内容:从某个角度来说,是由多个平级的view树构成。

    view树的顶级视图都是ViewRootImpl,或者说是ViewRootImpl通过setView设置的view。

2. 事件接收通道


WindowManagerService的创建和启动流程

1. 启动SystemServer:ZygoteInit.main() -> forkSystemServer() -> handleSystemServerProcess() -> zygoteInit() -> RuntimeInit.applicationInit() -> findStaticMain() -> MethodAndArgsCaller.run()

c++层通过JNI接口创建并启动了javaVM虚拟机

上图第2步的长流程:

 

 

2. SystemServer的关键步骤

对应的run方法: 

 WindowManagerService的创建与启动:



View绘制流程

scheduleTraversals -> TraversalRunnable -> (系统控制回调时机) ->  doTraversal -> performTraversals

从ViewRootImpl的performTraversals开始调用

【performMeasure->mView.measure->onMeasure】

ViewGroup的派生类会重写onMeasure(),通过measureChild去测量子View,

通过getChildMeasureSpec()方法及参数(父控件的宽高测量规格,View的LayoutParams)分别获取子View的宽高测量规格,

然后再去调用子View的measure()->onMeasure();

子View的onMeasure()->setMeasuredDimensionRaw方法中会给mMeasuredWidth,mMeasuredHeight测量宽高赋值,

所以onMeasure()后就能获取到测量宽高

【performLayout->mView.layout->onLayout】

ViewGroup的onLayout是抽象方法,其子类必须要实现onLayout()方法,遍历其子布局调用子View的layout方法,layout()在setFrame方法

中设置View的具体位置,View的onLayout是空实现方法。所以onLayout方法中可以获取到ViewGroup的真实宽高。

【performDraw->mView.draw->onDraw】

View的draw方法中分6步:

1.drawBackground(canvas)

2.onDraw(canvas)

3.dispatchDraw(canvas)->drawChild->child.draw()

4.onDrawForeground(canvas)


getChildMeasuredSpec()方法逻辑表(TODO)

 (待续)


View层的事件分发

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值