0xA06 Android 10 源码分析:WindowManager 视图绑定以及体系结构

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 0xA06 Android 10 源码分析:WindowManager 视图绑定以及体系结构

image.png


引言



  • 这是 Android 10 源码分析系列的第 6 篇
  • 分支:android-10.0.0_r14
  • 全文阅读大概 10 分钟


通过这篇文章你将学习到以下内容,将在文末总结部分会给出相应的答案


  • Acivity 和 Dialog 视图解析绑定过程?
  • Activity 的视图如何与 Window 关联的?
  • Window 如何与 WindowManager 关联?
  • Dialog 的视图如何与 Window 关联?


本文主要分析 Activity、Window、PhoneWindow、WindowManager 之间的关系,为我们后面的文章 「如何在 Andorid 系统里添加自定义View」 等等文章奠定基础,先来了解一下它们的基本概念


image.png


  • WindowManager:它是一个接口类,继承自接口 ViewManager,对 Window 进行管理
  • Window:它是一个抽象类,它作为一个顶级视图添加到 WindowManager 中,对 View 进行管理
  • PhoneWindow:Window唯一实现类,Window是一个抽象概念,添加到WindowManager的根容器
  • DecorView: 它是 PhoneWindow 内部的一个成员变量,继承自 FrameLayout,FrameLayout 继承自 ViewGroup


在分析他们之前的关系之前,我们先来回顾一下 Acivity 和 Dialog 视图解析绑定的过程


Acivity 和 Dialog 视图解析绑定的过程



Acivity 和 Dialog 相关的文章:



在之前的文章 分别介绍了 Acivity 和 自定义 Dialog 视图的解析和绑定,总的来说分为三步


  1. 调用 LayoutInflater 的 inflate 方法,深度优先遍历解析 View
  2. 调用 ViewGroup 的 addView 方法将子 View 添加到根布局中
  3. 调用 WindowManager 的 addView 方法添加根布局


LayoutInflater 的 inflate 方法有多个重载的方法,常用的是下面三个参数的方法


frameworks/base/core/java/android/view/LayoutInflater.java


public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
    return inflate(resource, root, root != null);
}


  • resource:要解析的 xml 布局文件 Id
  • root:表示根布局
  • attachToRoot:是否要添加到父布局 root 中


resource 其实很好理解就是资源 Id,而 root 和 attachToRoot 分别代表什么意思:


  • 当 attachToRoot == true 且 root != null 时,新解析出来的 View 会被 add 到 root 中去,然后将 root 作为结果返回
  • 当 attachToRoot == false 且 root != null 时,新解析的 View 会直接作为结果返回,而且 root 会为新解析的 View 生成 LayoutParams 并设置到该 View 中去
  • 当 attachToRoot == false 且 root == null 时,新解析的 View 会直接作为结果返回


当 View 解析完成之后,最后会调用 WindowManager 的 addView 方法,WindowManager 是一个接口类,继承自接口 ViewManager,用来管理 Window,它的实现类为 WindowManagerImpl,所以调用 WindowManager 的 addView 方法,实际上调用的是 WindowManagerImpl 的 addView 方法


frameworks/base/core/java/android/view/WindowManagerImpl.java


public final class WindowManagerImpl implements WindowManager {
    @UnsupportedAppUsage
    // 单例的设计模式
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    private final Context mContext;
    private final Window mParentWindow;
    ......
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        // mGlobal 是 WindowManagerGlobal 的实例
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }
    ......
}


mGlobal 是 WindowManagerGlobal 的实例,使用的单例设计模式,参数 mParentWindow 是 Window 的实例,实际上是委托给 WindowManagerGlobal 去实现的

到这里我们关于 Acivity 和 Dialog 视图的解析和添加过程大概介绍完了,关于 Dialog 的视图如何与 Window 绑定在 0xA05 Android 10 源码分析:Dialog 加载绘制流程以及在 Kotlin、DataBinding 中的使用 文章中介绍了,接下来分析一下 Activity、Window、WindowManager 的关系


Activity、Window、WindowManager 的关系



在 Activity 内部维护着一个 Window 的实例变量 mWindow

frameworks/base/core/java/android/app/Activity.java


public class Activity extends ContextThemeWrappe{
  private Window mWindow;
}


Window 是一个抽象类,它的具体实现类为 PhoneWindow,在 Activity 的 attach 方法中给 Window 的实例变量 mWindow 赋值


frameworks/base/core/java/android/app/Activity.java


final void attach(Context context, ActivityThread aThread,
        Instrumentation instr, IBinder token, int ident,
        Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        NonConfigurationInstances lastNonConfigurationInstances,
        Configuration config, String referrer, IVoiceInteractor voiceInteractor,
        Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
    ......
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    ......
    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    ......
}


  • 创建了 PhoneWindow 并赋值给 mWindow
  • 调用 PhoneWindow 的 setWindowManager 方法,这个方法的具体实现发生在 Window 中,最终调用的是 Window 的 setWindowManager 方法


frameworks/base/core/java/android/view/Window.java


public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
        boolean hardwareAccelerated) {
    ......
    // mWindowManager 是 WindowManagerImpl的实例变量
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}


将 WindowManager 转换为 WindowManagerImpl,之后调用 createLocalWindowManager 方法,并传递当前的 Window 对象,构建 WindowManagerImpl 对象,之后赋值给 mWindowManager


frameworks/base/core/java/android/view/WindowManagerImpl.java


public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
    return new WindowManagerImpl(mContext, parentWindow);
}


其实在 createLocalWindowManager 方法中,就做了一件事,将 Window 作为参数构建了一个 WindowManagerImpl 对象返还给调用处


总的来说,其实就是在 Activity 的 attach 方法中,通过调用 Window 的 setWindowManager 方法将 Window 和 WindowManager 关联在了一起

PhoneWindow 是 Window 的实现类,它是一个窗口,本身并不具备 View 相关的能力,实际上在 PhoneWindow 内部维护这一个变量 mDecor


frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java


public class PhoneWindow extends Window{
  // This is the top-level view of the window, containing the   window decor.
  private DecorView mDecor; 
  private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            // 完成DecorView的实例化
            mDecor = generateDecor(-1);
            ......
        }
        if (mContentParent == null) {
            // 调用 generateLayout 方法 要负责了DecorView的初始设置,诸如主题相关的feature、DecorView的背景
            mContentParent = generateLayout(mDecor);
        } 
        ......
    }
    // 完成DecorView的实例化
    protected DecorView generateDecor(int featureId) {
        ......
        return new DecorView(context, featureId, this, getAttributes());
    }
    // 调用 generateLayout 方法 要负责了DecorView的初始设置,
    // 诸如主题相关的feature、DecorView的背景,同时也初始化 contentParent
    protected ViewGroup generateLayout(DecorView decor) {
        ......
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        ......
    }
}


  • mDecor 是 window 的顶级视图,它继承自 FrameLayout,它的创建过程由 installDecor 完成,然后在 installDecor 方法中通过 generateDecor 方法来完成DecorView的实例化
  • 调用 generateLayout 方法 要负责了DecorView的初始设置,诸如主题相关的feature、DecorView的背景,同时也初始化 contentParent
  • mDecor 它实际上是一个 ViewGroup,当在 Activity 中调用 setContentView 方法,通过调用 inflater 方法把布局资源转换为一个 View,然后添加到 DecorView 的 mContenParnent 中


当 View 初始化完成之后,最后会进入 ActivityThread 的 handlerResumeActivity 方法,执行 执行了r.activity.makeVisible()方法


frameworks/base/core/java/android/app/ActivityThread.java


public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
            String reason) {
        ......
        if (r.activity.mVisibleFromClient) {
            r.activity.makeVisible();
        }
        ......
    }


最终调用 Activity 的 makeVisible 方法,把 decorView 添加到 WindowManage 中

frameworks/base/core/java/android/app/Activity.java


void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        wm.addView(mDecor, getWindow().getAttributes());
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}


到这里他们之间的关系明确了:


  • 一个 Activity 持有一个 PhoneWindow 的对象,而一个 PhoneWindow 对象持有一个 DecorView 的实例
  • PhoneWindow 继承自 Window,一个 Window 对象内部持有 mWindowManager 的实例,通过调用 setWindowManager 方法与 WindowManager 关联在一起
  • WindowManager 继承自 ViewManager,WindowManagerImpl 是 WindowManager 接口的实现类,但是具体的功能都会委托给 WindowManagerGlobal 来实现
  • 调用 WindowManager 的 addView 方法,实际上调用的是 WindowManagerImpl 的 addView 方法


总结



Acivity 和 Dialog 视图解析绑定过程?


  1. 调用 LayoutInflater 的 inflate 方法,深度优先遍历解析 View
  2. 调用 ViewGroup 的 addView 方法将子 View 添加到根布局中
  3. 调用 WindowManager 的 addView 方法添加根布局


Activity 的视图如何与 Window 关联的?


  • 在 Activity 内部维护着一个 Window 的实例变量 mWindow


frameworks/base/core/java/android/app/Activity.java


public class Activity extends ContextThemeWrappe{
  private Window mWindow;
}


  • 最后调用 Activity 的 makeVisible 方法,把 decorView 添加到 WindowManage 中


frameworks/base/core/java/android/app/Activity.java


void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        wm.addView(mDecor, getWindow().getAttributes());
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}


Window 如何与 WindowManager 关联?


在 Activity 的 attach 方法中,调用 PhoneWindow 的 setWindowManager 方法,这个方法的具体实现发生在 Window 中,最终调用的是 Window 的 setWindowManager 方法,将 Window 和 WindowManager 关联在了一起


frameworks/base/core/java/android/view/Window.java


public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
        boolean hardwareAccelerated) {
    ......
    // mWindowManager 是 WindowManagerImpl的实例变量
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}


Dialog 的视图如何与 Window 关联?


  • 在 Dialog 的构造方法中初始化了 Window 对象


frameworks/base/core/java/android/app/Dialog.java


Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
    ...
    // 获取WindowManager对象
    mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    // 构建PhoneWindow
    final Window w = new PhoneWindow(mContext);
    // mWindow 是PhoneWindow实例
    mWindow = w;
   ...
}


  • 调用 Dialog 的 show 方法,完成 view 的绘制和 Dialog 的显示


frameworks/base/core/java/android/app/Dialog.java


public void show() {
    // 获取DecorView
    mDecor = mWindow.getDecorView();
    // 获取布局参数
    WindowManager.LayoutParams l = mWindow.getAttributes();
    // 将DecorView和布局参数添加到WindowManager中
    mWindowManager.addView(mDecor, l);
}


参考文献




结语



致力于分享一系列 Android 系统源码、逆向分析、算法、翻译、Jetpack 源码相关的文章,正在努力写出更好的文章,如果这篇文章对你有帮助给个 star,文章中有什么没有写明白的地方,或者有什么更好的建议欢迎留言,欢迎一起来学习,在技术的道路上一起前进。


计划建立一个最全、最新的 AndroidX Jetpack 相关组件的实战项目 以及 相关组件原理分析文章,正在逐渐增加 Jetpack 新成员,仓库持续更新,可以前去查看:AndroidX-Jetpack-Practice, 如果这个仓库对你有帮助,请帮我点个赞,我会陆续完成更多 Jetpack 新成员的项目实践。


算法


由于 LeetCode 的题库庞大,每个分类都能筛选出数百道题,由于每个人的精力有限,不可能刷完所有题目,因此我按照经典类型题目去分类、和题目的难易程度去排序。


  • 数据结构: 数组、栈、队列、字符串、链表、树……
  • 算法: 查找算法、搜索算法、位运算、排序、数学、……


每道题目都会用 Java 和 kotlin 去实现,并且每道题目都有解题思路、时间复杂度和空间复杂度,如果你同我一样喜欢算法、LeetCode,可以关注我 GitHub 上的 LeetCode 题解:Leetcode-Solutions-with-Java-And-Kotlin,一起来学习,期待与你一起成长。


Android 10 源码系列


正在写一系列的 Android 10 源码分析的文章,了解系统源码,不仅有助于分析问题,在面试过程中,对我们也是非常有帮助的,如果你同我一样喜欢研究 Android 源码,可以关注我 GitHub 上的 Android10-Source-Analysis,文章都会同步到这个仓库。



工具系列



逆向系列




目录
相关文章
|
6月前
|
XML 前端开发 Java
Android App开发图像加工中卡片视图CardView和给图像添加装饰的讲解以及实战(附源码 简单易懂)
Android App开发图像加工中卡片视图CardView和给图像添加装饰的讲解以及实战(附源码 简单易懂)
254 0
|
1月前
|
Android开发 开发者
安卓应用开发中的自定义视图
【9月更文挑战第37天】在安卓开发的海洋中,自定义视图犹如一座座小岛,等待着勇敢的探索者去发现其独特之处。本文将带领你踏上这段旅程,从浅滩走向深海,逐步揭开自定义视图的神秘面纱。
35 3
|
3月前
|
供应链 物联网 区块链
未来触手可及:探索新兴技术的趋势与应用安卓开发中的自定义视图:从基础到进阶
【8月更文挑战第30天】随着科技的飞速发展,新兴技术如区块链、物联网和虚拟现实正在重塑我们的世界。本文将深入探讨这些技术的发展趋势和应用场景,带你领略未来的可能性。
|
3月前
|
测试技术 Android开发 Python
探索软件测试的艺术:从基础到高级安卓应用开发中的自定义视图
【8月更文挑战第29天】在软件开发的世界中,测试是不可或缺的一环。它如同艺术一般,需要精细的技巧和深厚的知识。本文旨在通过浅显易懂的语言,引领读者从软件测试的基础出发,逐步深入到更复杂的测试策略和工具的使用,最终达到能够独立进行高效测试的水平。我们将一起探索如何通过不同的测试方法来确保软件的质量和性能,就像艺术家通过不同的色彩和笔触来完成一幅画作一样。
|
5天前
|
搜索推荐 前端开发 Android开发
安卓应用开发中的自定义视图实现
【10月更文挑战第30天】在安卓开发的海洋中,自定义视图是那抹不可或缺的亮色,它为应用界面的个性化和交互体验的提升提供了无限可能。本文将深入探讨如何在安卓平台创建自定义视图,并展示如何通过代码实现这一过程。我们将从基础出发,逐步引导你理解自定义视图的核心概念,然后通过一个实际的代码示例,详细讲解如何将理论应用于实践,最终实现一个美观且具有良好用户体验的自定义控件。无论你是想提高自己的开发技能,还是仅仅出于对安卓开发的兴趣,这篇文章都将为你提供价值。
|
2月前
|
Android开发 开发者
安卓开发中的自定义视图:从入门到精通
【9月更文挑战第19天】在安卓开发的广阔天地中,自定义视图是一块充满魔力的土地。它不仅仅是代码的堆砌,更是艺术与科技的完美结合。通过掌握自定义视图,开发者能够打破常规,创造出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战应用,一步步展示如何用代码绘出心中的蓝图。无论你是初学者还是有经验的开发者,这篇文章都将为你打开一扇通往创意和效率的大门。让我们一起探索自定义视图的秘密,将你的应用打造成一件艺术品吧!
58 10
|
2月前
|
XML 编解码 Android开发
安卓开发中的自定义视图控件
【9月更文挑战第14天】在安卓开发中,自定义视图控件是一种高级技巧,它可以让开发者根据项目需求创建出独特的用户界面元素。本文将通过一个简单示例,引导你了解如何在安卓项目中实现自定义视图控件,包括创建自定义控件类、处理绘制逻辑以及响应用户交互。无论你是初学者还是有经验的开发者,这篇文章都会为你提供有价值的见解和技巧。
43 3
|
2月前
|
前端开发 Android开发 开发者
安卓应用开发中的自定义视图基础
【9月更文挑战第13天】在安卓开发的广阔天地中,自定义视图是一块神奇的画布,它允许开发者将想象力转化为用户界面的创新元素。本文将带你一探究竟,了解如何从零开始构建自定义视图,包括绘图基础、触摸事件处理,以及性能优化的实用技巧。无论你是想提升应用的视觉吸引力,还是追求更流畅的交互体验,这里都有你需要的金钥匙。
|
2月前
|
Android开发 UED 开发者
Android经典实战之WindowManager和创建系统悬浮窗
本文详细介绍了Android系统服务`WindowManager`,包括其主要功能和工作原理,并提供了创建系统悬浮窗的完整步骤。通过示例代码,展示了如何添加权限、请求权限、实现悬浮窗口及最佳实践,帮助开发者轻松掌握悬浮窗开发技巧。
259 1
|
2月前
|
API Android开发 数据安全/隐私保护
Android经典实战之窗口和WindowManager
本文介绍了Android开发中“窗口”的基本概念及其重要性。窗口是承载用户界面的基础单位,而`WindowManager`系统服务则负责窗口的创建、更新和移除等操作。了解这些概念有助于开发复杂且用户体验良好的应用。
50 2