(17/30)活动、窗、DecorView、ViewRoot

牛客高级系列专栏:

安卓(安卓系统开发也要掌握)


嵌入式


本人是2020年毕业于广东工业大学研究生:许乔丹,有国内大厂CVTE和世界500强企业安卓开发经验,该专栏整理本人对常见安卓高频开发面试题的理解;

网上安卓资料千千万,笔者将继续维护专栏,一杯奶茶价格不止提供答案解析,承诺提供专栏内容免费技术答疑,直接咨询即可。助您提高安卓面试准备效率,为您面试保驾护航!

正文开始⬇

安卓应用开发经常会接触到UI开发,除了对View的绘制流程需要有所了解,对我们目光所及的界面的层级也需要有所了解。Activity、Window、DecorView以及ViewRoot之间到底有什么联系呢?面试官可能会问:

  1. 请讲述Activity、Window、DecorView以及ViewRoot之间的层级关系⭐⭐⭐⭐⭐
  2. DecorView什么时候可见?⭐⭐⭐⭐

看完以下的解析,一定可以让面试官眼前一亮。

目录

  • 1、Activity、Window、DecorView以及ViewRoot之间的层级关系
    • 1.1 Activity
    • 1.2 Window
    • 1.3 DecorView
    • 1.4 ViewRoot
  • 2、DecorView源码分析
  • 3、DecorView的显示
  • 4、ViewRoot
  • 5、总结

1、Activity、Window、DecorView以及ViewRoot之间的层级关系

图片可以最直观看出这几个模块之间的层次关系。

alt

1.1 Activity

我们都知道可以Activity来创建可以触摸的视图界面,但其实Activity并不负责视图的控制。真正控制视图界面的是Window。每一个Activity包含一个Window。Activity主要负责视图界面的统筹,如添加、显示等,并通过一些特定的方法来和Window、View做交互。

1.2 Window

Window意味“窗口”,是视图界面真正的承载器。Window是一个接口类,实际的窗口是PhoneWindow类,该类内部有一个内部类DecorView。就可以通过创建DecorView来加载布局xml文件。

1.3 DecorView

DecorView是FrameLayout类的子类,通常认为DecorView是Android视图树的根节点,也就是最顶层的View。DecorView内部包含一个LinearLayout,在这个LinearLayout里面有上下三个部分,上面是个ViewStub,延迟加载的视图(应该是设置ActionBar,根据Theme设置),中间的是TitleView,根据Activity的主题设置的,有的布局就没有这个标题栏,最下面的是ContentViews,这是最重要的一部分,我们平时自定义的布局文件通过setContentView()方法加载,其实就是加载到这个ContentViews里面,成为其唯一的子View。Window 通过WindowManager将DecorView加载其中,并将DecorView交给ViewRoot,进行视图绘制以及其他交互。通过一个实际的DecorView文件加深理解:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:fitsSystemWindows="true"
    android:orientation="vertical">
    <!-- Popout bar for action modes -->
    <ViewStub
        android:id="@+id/action_mode_bar_stub"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inflatedId="@+id/action_mode_bar"
        android:layout="@layout/action_mode_bar"
        android:theme="?attr/actionBarTheme" />

    <FrameLayout
        style="?android:attr/windowTitleBackgroundStyle"
        android:layout_width="match_parent"
        android:layout_height="?android:attr/windowTitleSize">

        <TextView
            android:id="@android:id/title"
            style="?android:attr/windowTitleStyle"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@null"
            android:fadingEdge="horizontal"
            android:gravity="center_vertical" />
    </FrameLayout>

    <FrameLayout
        android:id="@android:id/content"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1"
        android:foreground="?android:attr/windowContentOverlay"
        android:foregroundGravity="fill_horizontal|top" />
</LinearLayout>

1.4 ViewRoot

ViewRoot作用非常重大。所有View绘制、触摸事件分发、界面刷新等都是通过它来执行或传递的。ViewRoot对应ViewRootImpl类,它是连接WindowManagerService和DecorView的纽带

ViewRoot并不属于View树的一份子。从源码实现上来看,它既非View的子类,也非View的父类,但是,它实现了ViewParent接口,这让它可以作为View的名义上的父视图。RootView继承了Handler类,可以接收事件并分发,Android的所有触屏事件、按键事件、界面刷新等事件都是通过ViewRoot进行分发的。

2、DecorView源码分析

从上面的介绍可以看出DecorView的重要地位,这一节,通过阅读源码,进一步弄清楚:

  • Activity、Window、DecorView以及ViewRoot之间的层级嵌套关系;
  • DecorView的创建和显示;

为了读者可以更加完整的了解上面两个问题,我们从handleLaunchActivity()方法开始追溯,该方法是Activity启动的本地操作入口,完成整个Activity的启动流程。 以下源码来自Android9.0.0/frameworks/base/core/java/android/app/ActivityThread.java:

public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
    ...
    final Activity a = performLaunchActivity(r, customIntent); // 1

    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        reportSizeConfigurations(r);
        if (!r.activity.mFinished && pendingActions != null) {
            pendingActions.setOldState(r.state);
            pendingActions.setRestoreInstanceState(true);
            pendingActions.setCallOnPostCreate(true);
        }
    } 
    ...
    return a;
}

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
            ...
 activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback); // 2
            ...
}

在Acitivy的创建流程有如下调用关系:

handleLaunchActivity()-> [注释1]performLaunchActivity()-> [注释2]activity.attach()

继续跟踪源码就到了activity.attach(),其源码在/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,
        NonConfigurationInstan

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Android高频面试题全解析 文章被收录于专栏

#提供免费售后答疑!!花一杯奶茶的钱获得安卓面试答疑服务,稳赚不赔# Android发展已经很多年,安卓资料网上千千万,本专栏免费提供专栏内容技术答疑!!私聊当天必回。在阅读过程或者其他安卓学习过程有疑问,都非常欢迎私聊交流。

全部评论
WindowManagerGlobal的addView()方法中不仅会将DecorView添加到Window中, 这里不太懂,请问下把DecorView添加到Window中的具体代码是什么呢?
点赞 回复 分享
发布于 2023-11-16 20:39 广东

相关推荐

佛系的本杰明反对画饼:个人看法,实习经历那段是败笔,可以删掉,它和你目标岗位没什么关系,没有用到什么专业技能,甚至会降低你项目经历内容的可信度。个人技能那里可以再多写一点,去boss直聘上看别人写的岗位要求,可以把你会的整合一下,比如熟悉常规的开关电源拓扑结构(BUCK、正激、反激、LLC等),熟悉常用的通信总线协议和通信接口,如UART,IIC,SPI等。简历首先是HR看的,HR大多不懂技术,会从简历里去找关键字,你没有那些关键字他可能就把你筛掉了,所以个人技能尽量针对着岗位描述写一下。还有电赛获佳绩,获奖了就写什么奖,没获奖就把获佳绩删了吧,要不会让人感觉夸大。
点赞 评论 收藏
分享
评论
16
14
分享

创作者周榜

更多
牛客网
牛客企业服务