在android的App开发过程中,UI流畅刷新是非常关键的。
android是怎么样进行UI刷新的呢?当然离不开大名鼎鼎的VSync机制。
举个栗子,以画面上有个控件(TextView)需要重新绘制进行流程的简单介绍
首先一个控件更新后,会调用到基类的invalidate()函数
在View中会根据描画树的结构进行递归调用,一直到ViewRootImpl中的invalidate,然后进行vsync的请求。
详细请参考如下时序图:
分三个大块,1. 初始化,2. vsync请求,3. vsync执行
描画的时序图
从上图中只能看到将vsync的请求发到底层,然后再怎么调用回来,调用viewrootimpl的著名遍历刷新函数上来。
首先应该从choreograph中开始说起。
在ViewRootImpl.java中通过mChoreographer = Choreographer.getInstance();获取Choreographer对象,
如果此进程是第一次调用此函数,则通过Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);创建一个对象。
在Choreographer的构造函数中,创建了对象FrameDisplayEventReceiver。
mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper, vsyncSource) : null;
因为FrameDisplayEventReceiver 类继承DisplayEventReceiver
在DisplayEventReceiver的构造中通过JNI函数nativeInit,先构造NativeDisplayEventReceiver,以及基类DisplayEventDispatcher的构造
在DisplayEventDispatcher的构造中,创建了DisplayEventReceiver mReceiver.
而DisplayEventReceiver构造中,一个非常重要的对象被创建出来
mEventConnection = sf->createDisplayEventConnection(vsyncSource);
构造函数如下:
DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
sp sf(ComposerService::getComposerService());
if (sf != NULL) {
mEventConnection = sf->createDisplayEventConnection(vsyncSource);
if (mEventConnection != NULL) {
mDataChannel = std::make_unique<:bittube>();
mEventConnection->stealReceiveChannel(mDataChannel.get());
}
}
}
上述流程走完后,调用NativeDisplayEventReceiver的initialize,然后通过mLooper->addFd()监听vsync信号
当发生vsync信号后,会调用looper的handleEvent函数。
此时就能将vsync信号转发到了choreographer中,然后在转到ViewRootImpl中进行描画的具体的动作。
SurfaceFlinger中的刷新时序图: