还是那张图,先回忆一下
从View开始
从应用的角度来讲,View有两个方法我们比较熟悉,一个是requestLayout,一个是invalidate,先看一下代码
//View.java
public void requestLayout() {
if (mParent != null && !mParent.isLayoutRequested()) {
mParent.requestLayout();
}
}
//invalidate()最终会调用到invalidateInternal
void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
boolean fullInvalidate) {
// Propagate the damage rectangle to the parent view.
final AttachInfo ai = mAttachInfo;
final ViewParent p = mParent;
if (p != null && ai != null && l < r && t < b) {
final Rect damage = ai.mTmpInvalRect;
damage.set(l, t, r, b);
p.invalidateChild(this, damage);
}
}
}
- 这两个方法最终其实都会调用到ViewRootImpl中的scheduleTraversals(),所不同的是invalidate()会指定dirty区域,dirty区域就是调用invalidate者对应view的区域,关于dirty区域后续再详述。
- 这里需要注意两个对象:
。mParent: 这个是ViewParent类型,是个接口,ViewRootImpl实现了这个接口,在ViewRootImpl初始化的时候调用setView会把自己的引用传递给View
。mAttachInfo:AttachInfo对象,是View的内部类,View都会附着到一个Window上面去,而这个mAttachInfo就包含了附着相关的一些信息 -
关于ViewRootImpl的信息会在介绍ViewRoot的时候再说,这里先看看View和ViewRootImpl类图关系
View_class.png
//ViewRootImpl.java
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
- mChoreographer: ViewRootImpl在初始化的时候初始化该对象,详见Choreography第一部分
- mTraversalScheduled:这个变量用来标志发起了view遍历请求,可以看到同一时间ViewRoot只能进行一个请求,其实也很好理解,这个只是请求,VSync回来之后才会进行view的遍历绘制,多个请求也没有意义。
- mTraversalRunnable这个是回调,这里把回调设置给Choreographer,类型为CALLBACK_TRAVERSAL,这个回调在讲解第三部分的时候会用到,这里先记下。
重点关注方法postCallback,它最终会调用到postCallbackDelayedInternal
//Choreographer.java
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) { //立即发起,这里采用的是立即
scheduleFrameLocked(now);
} else { //delay一段时间之后再发起
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
- mCallbackQueues:在讲解Choreographer初始化的时候提到过,mCallbackQueues是一个CallbackQueue类型的数组,CallbackQueue相当于一个链表,所以mCallbackQueues实际上是维护多个链表,每个链表代表一种类型的回调,每一种回调都可能包含多个回调。目前代码支持如下几种类型的回调
{
CALLBACK_INPUT
CALLBACK_ANIMATION
CALLBACK_INSETS_ANIMATION
CALLBACK_TRAVERSAL
}
我们现在正在讲解的就是第四种CALLBACK_TRAVERSAL
接下来会调用scheduleFrameLocked
//Choreographer.java
private void scheduleFrameLocked(long now) {
scheduleVsyncLocked();
}
private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
}
//DisplayEventReceiver.java
public void scheduleVsync() {
if (mReceiverPtr == 0) {
...
} else {
nativeScheduleVsync(mReceiverPtr);
}
}
mReceiverPtr 在Choreography 初始化的时候提过,实际上它是NativeDisplayEventReceiver对象的指针对应的地址,通过这个地址可以找到对应的对象
其它的这里都是顺序调用,没有特殊需要注意的
//android_view_DisplayEventReceiver.cpp
static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
sp<NativeDisplayEventReceiver> receiver =
reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
status_t status = receiver->scheduleVsync();
}
首先根据指针地址receiverPtr找到对象,然后调用scheduleVsync(),注意这里实际上调用的是DisplayEventDispatcher的方法,因为NativeDisplayEventReceiver实际上是DisplayEventDispatcher的子类
//DisplayEventDispatcher.cpp
status_t DisplayEventDispatcher::scheduleVsync() {
if (!mWaitingForVsync) {
status_t status = mReceiver.requestNextVsync();
mWaitingForVsync = true;
}
return OK;
}
mWaitingForVsync 为true表示当前已经申请并等待下一个VSync信号了,那就没必要处理这次申请了,直接pass。接着调用requestNextVsync
//DisplayEventReceiver.cpp
status_t DisplayEventReceiver::requestNextVsync() {
if (mEventConnection != nullptr) {
mEventConnection->requestNextVsync();
return NO_ERROR;
}
return NO_INIT;
}
mEventConnection 的初始化参考Choreographer 编舞者(一)
//EventThread.cpp
void EventThreadConnection::requestNextVsync() {
mEventThread->requestNextVsync(this);
}
void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
std::lock_guard<std::mutex> lock(mMutex);
if (connection->vsyncRequest == VSyncRequest::None) {
connection->vsyncRequest = VSyncRequest::Single;
mCondition.notify_all();
}
}
lock_guard: 局部锁,局部变量lock加锁,超出lock作用域自动解锁
vsyncRequest:在connection初始化的时候初始值为VSyncRequest::None表示当前没有request,然后在这里置为Single,然后去触发条件mCondition.notify_all(),这会触发循环函数threadMain。
lock_guard以及condition_variable相关知识是属于C++的基本知识,可自行查询。
//EventThread.cpp
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
while (mState != State::Quit) {
if (mState != nextState) {
if (mState == State::VSync) {
mVSyncSource->setVSyncEnabled(false);
} else if (nextState == State::VSync) {
mVSyncSource->setVSyncEnabled(true);
}
mState = nextState;
}
// Wait for event or client registration/request.
if (mState == State::Idle) {
mCondition.wait(lock); //这里等待触发条件
}
}
}
这里根据前面设置的vsyncRequest来判断出nextState为State::VSync,所以会去调用mVSyncSource->setVSyncEnabled(true),关于mVSyncSource以及threadMain的其它分支请参看EventThread初始化流程。
//DispSyncSource.cpp
void DispSyncSource::setVSyncEnabled(bool enable) {
std::lock_guard lock(mVsyncMutex);
if (enable) {
status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
static_cast<DispSync::Callback*>(this),
mLastCallbackTime);
} else {
...
}
mEnabled = enable;
}
这里enable为true,先不看false情况。
代码很简单,就是把this设置为回调,继续:
status_t DispSync::addEventListener(const char* name, nsecs_t phase, Callback* callback,
nsecs_t lastCallbackTime) {
return mThread->addEventListener(name, phase, callback, lastCallbackTime);
}
status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback,
nsecs_t lastCallbackTime) {
EventListener listener;
listener.mName = name;
listener.mPhase = phase;
listener.mCallback = callback;
mEventListeners.push_back(listener);
mCond.signal();
return NO_ERROR;
}
主要功能是组装listener然后添加到mEventListeners中,然后发出信号signal,告诉threadLoop有监听者来临,如果有VSync的时候需要通知。
mEventListeners是一个vector,保存了所有对VSync感兴趣的监听者,包括这里我们注册的app,也包括后续会讲到的sf。
走到这里,view申请监听VSync的流程就走完了,但有VSync信号来临,就会通知对应的注册者。