UI核心 - UI绘制流程及原理

1. View添加到屏幕窗口的源码分析

入口:在Activity的onCreate中调用setContentView传入布局资源ID。 接着调用 :getWindow().setContentView(layoutResID); 其中 getWindow,返回就 Window 的唯一实现类 PhoneWindow。

java 复制代码
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

PhoneWindow:

java 复制代码
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            ...
        }
        ...
    }
java 复制代码
    private void installDecor() {
        if (mDecor == null) {
            mDecor = generateDecor(-1); // return new DecorView 
           ...
        } else {
            ...
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);
            ...
        }
    }

在 PhoneWindow 的 setContentView 中,会调用 installDecor 里面的方法执行 generateDecor 创建 DecorView。 DecorView继承自FrameLayout,是应用窗口的顶层View容器。 然后将 mDecor 传进 generateLayout, 该方法根据系统主题属性(如是否有ActionBar、浮动窗口等)确定不同的layoutResource(例如R.layout.screen_simple)。 通过 mDecor.onResourcesLoaded(mLayoutInflater, layoutResource); 将得到的布局资源添加到 DecorView 中。 然后通过 findViewById 获取 id 为 com.android.internal.R.id.content 的基础布局,一般为 FrameLayout,后面我们的界面就是绘制在这个布局里面的。 最终返回这个 contentParent

小结

PhoneWindow持有DecorView。DecorView中包含根据主题生成的基础布局(如screen_simple),该基础布局通常包含标题栏(Title/ActionBar)和内容区域(ID为content的FrameLayout)。我们的XML布局最终被添加到这个content容器中。

2. View绘制流程的触发机制

绘制的入口是ActivityThread的handleResumeActivity方法。 该方法在执行performResumeActivity(回调onResume)后,初始化WindowManager.LayoutParams,并调用WindowManager的addView方法。

WindowManager 来源:

  • Activity中的WindowManager接口实现类为WindowManagerImpl。
  • WindowManagerImpl的addView方法委托给WindowManagerGlobal的addView方法。
  • WindowManagerGlobal.addView中创建ViewRootImpl对象,并将DecorView、布局参数等与之关联。

关键调用:root.setView(view, wparams, panelParentView),其中root即为ViewRootImpl实例。

3. 绘制核心流程:PerformTraversals

在ViewRootImpl.setView中调用requestLayout()。该方法首先通过checkThread()确保当前操作在主线程执行,随后调用scheduledTraversals()。 scheduledTraversals()通过Choreographer(编舞者) post一个TraversalRunnable。当VSync信号到来时,TraversalRunnable的run方法被执行,进而调用doTraversal()。 doTraversal()的核心是调用performTraversals()。在此方法中,依次执行UI绘制的三个关键步骤:

  • 测量 (Measure):调用performMeasure(),确定View的大小。
  • 布局 (Layout):调用performLayout(),确定View的位置。
  • 绘制 (Draw):调用performDraw(),将View内容渲染到屏幕上。
相关推荐
mmsx1 小时前
Android 一个设备多个 App 抢:跨进程共享服务的架构设计
android·kotlin·app
mmsx1 小时前
Android GIS系列 栅格怎么存、格网怎么归算:两个容易混淆的 GIS 链路
android·性能优化·app
陈柒吖1 小时前
安卓代码加固(1):加密DEX
android·前端
mmsx1 小时前
Android GIS系列 串口、蓝牙、USB、网络:一套统一抽象怎么扛住四种通道
android·app·产品
二流小码农1 小时前
鸿蒙开发:ArrayList,可不会让UI更新哦
android·ios·harmonyos
hai_android1 小时前
深入理解 Java 的四种引用:强引用、软引用、弱引用、虚引用
android·kotlin·android jetpack
恋猫de小郭1 小时前
Flutter Golden Tests:给 AI Agent 的 UI 测试系统
android·前端·flutter
知昂七昂1 小时前
AOSP编译:敲下 `lunch xxx-userdebug`,你知道系统偷偷干了什么吗?
android
千里马学框架5 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation