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);
}

大概的流程图如下:

相关推荐
阿巴斯甜5 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker5 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95276 小时前
Andorid Google 登录接入文档
android
黄林晴7 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab20 小时前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android