Android窗口机制
发布日期:2021-06-29 02:38:47 浏览次数:3 分类:技术文章

本文共 5346 字,大约阅读时间需要 17 分钟。

DecorView通过PhoneWindow与WindowManagerService通信原理图

在这里插入图片描述

每个Activity都有一个Window对象,这个对象是PhoneWindow类型的。

每个Window对象里面都维护着一个WindowManager对象。

Activity里面添加一个View是通过WindowManager的addView()方法实现的

相关关键类

高层级,系统窗口管理服务

一个顶级窗口的外观和行为策略的一个抽象基类。

Window并不是真实存在的,它表示一种抽象的功能集合,View才是Android中的视图呈现形式,绘制到屏幕上的是View不是Window,但是View不能单独存在,它必需依附在Window这个抽象的概念上面,Android中需要依赖Window提供视图的有Activity,Dialog,Toast,PopupWindow,StatusBarWindow(系统状态栏),输入法窗口等,因此Activity,Dialog等都维护着一个Window对象。当我们调用Activity的setContentView()时,其实最终会调用Window的setContentView(),当我们调用Activity的findViewById()时,其实最终调用的是Window的findViewById()。

对 Window 的操作是通过 WindowManager 来完成的。

WindowManager是一个接口,里面常用的方法有:添加View,更新View和删除View,WindowManager继承自ViewManager,这三个方法定义在ViewManager中:

public interface ViewManager{
public void addView(View view, ViewGroup.LayoutParams params); public void updateViewLayout(View view, ViewGroup.LayoutParams params); public void removeView(View view);}

低层次,负责与系统窗口管理服务进行操作通信,与Context进行关联。
是WindowManager的实现类,大部分工作都通过WindowManagerGlobal来实现。
低层次,负责与系统窗口管理服务进行操作通信,不与Context进行关联。

ViewRootImpl是一个视图层次结构的顶部,它实现了View与WindowManager之间所需要的协议,作为WindowManagerGlobal中大部分的内部实现,也就说WindowManagerGlobal方法最后还是大部分调用了ViewRootImpl。
类似 ApplicationThread 负责跟AMS通信一样,ViewRootImpl 的一个重要职责就是跟 WMS 通信,它通过静态变量 sWindowSession(IWindowSession实例,在中创建)与 WMS 进行通信。

源码分析

ActivityThread.handleResumeActivity()方法 :

@Override    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) {
...//其他代码 if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true; wm.addView(decor, l); } else {
// The activity will get a callback for this {@link LayoutParams} change // earlier. However, at that time the decor will not be set (this is set // in this method), so no action will be taken. This call ensures the // callback occurs with the decor set. a.onWindowAttributesChanged(l); } } ...//其他代码 }

调用WindowManagerImpl.addView() :

@Override    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params); mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); }

调用WindowManagerGlobal.addView():

public void addView(View view, ViewGroup.LayoutParams params,            Display display, Window parentWindow) {
...//其他代码 root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); mViews.add(view); mRoots.add(root); mParams.add(wparams); // do this last because it fires off messages to start doing things try {
root.setView(view, wparams, panelParentView); } catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up. if (index >= 0) {
removeViewLocked(index, true); } throw e; } } }

调用ViewRootImpl.java的setView方法

/**     * We have one child     */    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
...//其他代码 // Schedule the first layout -before- adding to the window // manager, to make sure we do the relayout before receiving // any other events from the system. requestLayout(); //请求布局 if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel(); } mForceDecorViewVisibility = (mWindowAttributes.privateFlags & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0; try {
mOrigWindowType = mWindowAttributes.type; mAttachInfo.mRecomputeGlobalAttributes = true; collectViewAttributes(); res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mWinFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel); } ...//其他代码}

res = mWindowSession.addToDisplay() 调用了的addToDisplay()方法:

@Override    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,            int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,            Rect outStableInsets, Rect outOutsets,            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame, outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel); }

调用mService.addWindow()方法添加Window,这个mService其实就是对象,也就是说布局最终是由 WindowManagerService 来添加的。

分析到这里可以看到,ViewRootImpl是通过 mWindowSession(来自的sWindowSession对象)和WindowManagerService通信的。

参考:

转载地址:https://blog.csdn.net/yzpbright/article/details/104583793 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Java并发编程之线程、多线程和线程池专题
下一篇:Android 编舞者Choreographer

发表评论

最新留言

不错!
[***.144.177.141]2024年04月25日 20时28分53秒