首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Activity启动时View首次绘制的源码深度解析:从handleResumeActivity()到performTraversals()

Activity启动时View首次绘制的源码深度解析:从handleResumeActivity()到performTraversals()

原创
作者头像
李林LiLin
发布2025-07-18 16:50:07
发布2025-07-18 16:50:07
2440
举报
文章被收录于专栏:Android进阶编程Android进阶编程

一、整体流程概览

二、源码深度解析

1、ActivityThread.handleResumeActivity()

这是整个绘制流程的起点,位于frameworks/base/core/java/android/app/ActivityThread.java

代码语言:txt
复制
public void handleResumeActivity(IBinder token, boolean finalStateRequest, 
        boolean isForward, String reason) {
    
    // 1. 执行Activity的onResume生命周期
    final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
    
    if (r != null) {
        final Activity a = r.activity;
        //...
        if (r.window == null && !a.mFinished && willBeVisible) {
            // 2. 获取DecorView
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);
            
            // 3. 获取WindowManager
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            
            // 4. 关键调用:添加DecorView到窗口系统
            wm.addView(decor, l);
        }
    }
}

2、WindowManagerGlobal.addView()

此方法位于frameworks/base/core/java/android/view/WindowManagerGlobal.java

代码语言:txt
复制
public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
    
    synchronized (mLock) {
        // 1. 创建ViewRootImpl实例
        ViewRootImpl root = new ViewRootImpl(view.getContext(), display);
        
        // 2. 保存视图引用
        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);
        
        try {
            // 3. 核心调用:关联视图与ViewRootImpl
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            // 异常处理
        }
    }
}

3、ViewRootImpl.setView()

位于frameworks/base/core/java/android/view/ViewRootImpl.java

代码语言:txt
复制
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        if (mView == null) {
            mView = view; // 保存DecorView引用
            
            // 1. 请求首次布局
            requestLayout();
            
            // 2. 通过Binder与WMS通信
            try {
                mWindowSession.addToDisplayAsUser(...);
            } catch (RemoteException e) {
                // 异常处理
            }
            
            // 3. 设置输入事件接收器
            mInputEventReceiver = new WindowInputEventReceiver(...);
        }
    }
}

4、ViewRootImpl.requestLayout()

代码语言:txt
复制
@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        // 1. 检查是否在主线程
        checkThread();
        
        // 2. 标记布局请求
        mLayoutRequested = true;
        
        // 3. 调度遍历任务
        scheduleTraversals();
    }
}

5、ViewRootImpl.scheduleTraversals()

代码语言:txt
复制
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        
        // 1. 插入同步屏障(确保UI绘制优先)
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        
        // 2. 通过Choreographer注册VSync回调
        mChoreographer.postCallback(
            Choreographer.CALLBACK_TRAVERSAL, 
            mTraversalRunnable, // 关键回调
            null
        );
        
        // 3. 通知渲染管道
        if (!mUnbufferedInputDispatch) {
            scheduleConsumeBatchedInput();
        }
    }
}

6、VSync信号处理

当VSync信号到达时,触发回调链:

代码语言:txt
复制
// mTraversalRunnable的实现
final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        doTraversal();
    }
}

void doTraversal() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        
        // 1. 移除同步屏障
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
        
        // 2. 执行核心遍历
        performTraversals();
    }
}

7、 ViewRootImpl.performTraversals()

这是整个绘制流程的核心(精简版):

代码语言:txt
复制
private void performTraversals() {
    final View host = mView; // 即DecorView
    
    // 第一阶段:预测量
    if (mFirst) {
        // 1. 与WMS通信获取窗口尺寸
        relayoutResult = relayoutWindow(params, ...);
        
        // 2. 收集View树所需系统配置
        collectViewAttributes();
    }
    
    // 第二阶段:测量(Measure)
    if (layoutRequested) {
        // 1. 创建MeasureSpec
        int childWidthMeasureSpec = getRootMeasureSpec(...);
        int childHeightMeasureSpec = getRootMeasureSpec(...);
        
        // 2. 执行DecorView的测量
        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    }
    
    // 第三阶段:布局(Layout)
    if (didLayout) {
        // 1. 执行DecorView的布局
        performLayout(lp, mWidth, mHeight);
        
        // 2. 处理键盘导航变化
        if ((host.mPrivateFlags & PFLAG_FOCUSED) != 0) {
            host.restoreDefaultFocus();
        }
    }
    
    // 第四阶段:绘制(Draw)
    if (!cancelDraw && !newSurface) {
        // 1. 判断是否需要完整重绘
        boolean fullRedrawNeeded = mFullRedrawNeeded;
        
        // 2. 执行绘制
        performDraw();
    }
    
    // 第五阶段:清理
    if (mFirst) {
        mFirst = false; // 标记首次遍历完成
    }
}

三、三大核心流程详解

1、测量阶段 (performMeasure)

代码语言:txt
复制
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
    try {
        // 调用DecorView的measure()方法
        mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}

核心机制

  • 从DecorView开始递归遍历整个View树
  • 父View通过MeasureSpec向子View传递约束条件
  • 子View通过onMeasure()计算自身尺寸

2、布局阶段 (performLayout)

代码语言:txt
复制
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
        int desiredWindowHeight) {
    
    // 设置宿主窗口尺寸
    host.setFrame(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
    
    // 执行DecorView的layout()
    host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
}

核心机制

  • 从DecorView开始递归调用layout()
  • 父View通过onLayout()确定子View位置
  • 使用setFrame()设置每个View的最终位置

3、 绘制阶段 (performDraw)

代码语言:txt
复制
private void performDraw() {
    try {
        boolean canUseAsync = draw(fullRedrawNeeded);
        //...
    } finally {
        mIsDrawing = false;
    }
}

private boolean draw(boolean fullRedrawNeeded) {
    if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
            scalingRequired, dirty, surfaceInsets)) {
        return false;
    }
    return true;
}

private boolean drawSoftware(Surface surface, AttachInfo attachInfo,
        int xoff, int yoff, boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
    
    // 1. 锁定Canvas
    Canvas canvas = surface.lockCanvas(dirty);
    
    try {
        // 2. 执行DecorView的draw()
        mView.draw(canvas);
    } finally {
        // 3. 解锁并提交渲染
        surface.unlockCanvasAndPost(canvas);
    }
    return true;
}

核心机制

  • 通过Surface获取Canvas绘图对象
  • 从DecorView开始递归调用draw()
  • 绘制顺序:背景 → 自身内容 → 子View → 装饰(如滚动条)
  • 通过GPU或软件渲染器完成最终渲染

四、关键设计要点

1、VSync同步机制

  • 通过Choreographer实现绘制与显示刷新率同步
  • 避免撕裂现象,保证帧完整性
  • 按60fps计算,每帧处理窗口为16.6ms

2、三级缓存优化

3、同步屏障(Sync Barrier)

  • 确保UI绘制消息优先处理
  • 实现方式:Looper.getQueue().postSyncBarrier()
  • 遍历完成后通过removeSyncBarrier()移除

4、增量更新优化

  • 通过mDirty区域标记需要重绘的部分
  • 减少不必要的GPU渲染开销
  • 特别优化动画场景下的性能表现

五、性能优化启示

1、减少布局层级

  • 每增加一层布局增加6ms测量时间
  • 使用<merge>标签或ConstraintLayout优化

2、避免主线程阻塞

代码语言:txt
复制
// 错误示例:在onResume中直接获取宽高
protected void onResume() {
    super.onResume();
    int width = myView.getWidth(); // 返回0
}

// 正确做法
protected void onResume() {
    super.onResume();
    myView.post(() -> {
        int width = myView.getWidth(); // 正确值
    });
}

3、绘制优化策略

  • 使用ViewStub延迟加载复杂布局
  • 通过canvas.clipRect()限制绘制区域
  • 对静态内容开启setLayerType(LAYER_TYPE_HARDWARE)

4、首帧加速技巧

  • onCreate()中预加载数据
  • 使用SplashScreen API优化启动体验
  • 对初始化任务进行分级调度

六、总结

Activity的View首次绘制是一个精密的系统级协作过程:

  1. 生命周期触发handleResumeActivity()启动流程
  2. 视图挂载:通过WindowManager.addView()关联视图与ViewRootImpl
  3. VSync调度Choreographer协调硬件信号与软件绘制
  4. 三大流程:Measure → Layout → Draw 递归遍历视图树
  5. 渲染提交:通过SurfaceFlinger合成最终图像

理解此流程对开发高性能UI至关重要,尤其在优化启动速度和滚动流畅性时,能帮助开发者准确定位性能瓶颈。建议结合Systrace工具实际验证绘制流程各阶段耗时,实现精准优化。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、整体流程概览
  • 二、源码深度解析
    • 1、ActivityThread.handleResumeActivity()
    • 2、WindowManagerGlobal.addView()
    • 3、ViewRootImpl.setView()
    • 4、ViewRootImpl.requestLayout()
    • 5、ViewRootImpl.scheduleTraversals()
    • 6、VSync信号处理
    • 7、 ViewRootImpl.performTraversals()
  • 三、三大核心流程详解
    • 1、测量阶段 (performMeasure)
    • 2、布局阶段 (performLayout)
    • 3、 绘制阶段 (performDraw)
  • 四、关键设计要点
    • 1、VSync同步机制
    • 2、三级缓存优化
    • 3、同步屏障(Sync Barrier)
    • 4、增量更新优化
  • 五、性能优化启示
    • 1、减少布局层级
    • 2、避免主线程阻塞
    • 3、绘制优化策略
    • 4、首帧加速技巧
  • 六、总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档