Android View的绘制流程

1.不管是View的添加,还是调用View的刷新方法invalidate()或者requestLayout(),绘制都是从ViewRootImpl的scheduleTraversals()方法开始

java 复制代码
void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            ......
        }
    }

首先会发送一个同步屏障消息,以便及时响应UI刷新的异步消息。

然后向Choreographer注册了一个Vsync信号的监听。

2.Vsync信号通过Choreographer回调之后,会执行TraversalRunnable里面的doTraversal()方法

java 复制代码
void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            performTraversals();
            
        }
    }

doTraversal()方法里首先会移除同步屏障消息,然后执行performTraversals()方法。

java 复制代码
performTraversals(){
	performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
	
	performLayout(lp, mWidth, mHeight);

	performDraw(mActiveSurfaceSyncGroup)
}

performTraversals()方法里面就会执行我们熟悉的测量、布局、绘制的方法。

3.当测量和布局执行完成后,会执行performDraw()方法,这里分为了开启硬件加速和不开启硬件加速两种绘制方式。

java 复制代码
private boolean performDraw(@Nullable SurfaceSyncGroup surfaceSyncGroup) {
	draw(fullRedrawNeeded, surfaceSyncGroup, mSyncBuffer);
}
private boolean draw(boolean fullRedrawNeeded, @Nullable SurfaceSyncGroup activeSyncGroup,
            boolean syncBuffer) {
	if (isHardwareEnabled()) { //如果开启了硬件加速,使用单独的渲染线程
		mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
	} else { //使用CPU调用libSkia库渲染
		drawSoftware(surface, mAttachInfo,xOffset,yOffset,scalingRequired, dirty, surfaceInsets)
	}
	
}

4.开启硬件加速的绘制方式

开启硬件加速,会创建一个RenderThread线程,MainThread会把需要绘制的内容记录到DisplayList里面,并通知RenderThread线程开始渲染,而此时MainThread可以从这个绘制任务中解脱出来。

java 复制代码
void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {
	updateRootDisplayList(view, callbacks); //同步View内容到DisplayList
	......
	syncAndDrawFrame(frameInfo); // 通知渲染线程开始工作
}

RenderThread会调用libhwui库去做渲染,使用GPU的硬件资源。

不管是否开启硬件加速,只要是绘制,都会先申请空的图形缓冲(dequenebuffer),然后做内容渲染,然后再把有内容的图形缓冲加入消费队列(quenebuffer)。

5.使用软件方式绘制

软件方式绘制渲染,首先通过调用Surface的lockCanvas方法,申请图形缓冲,并关联到Skia图形库;然后调用view的draw方法绘制,这里会调用到View的ondraw()回调方法;绘制完后,通过unlockCanvasAndPost方法把绘制好的缓冲加入到图形缓冲队列,SurfaceFlinger会消费图形缓冲并合成缓冲帧,通过HWC给到屏幕驱动显示。

java 复制代码
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
	canvas = mSurface.lockCanvas(dirty);       
	mView.draw(canvas);
	surface.unlockCanvasAndPost(canvas);
}

大概的流程图如下:

相关推荐
千里马学框架3 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台3 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone3 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc3 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo3 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077003 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼3 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone3 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen3 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone3 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui