Choreographer 编舞者(二)

还是那张图,先回忆一下


choreographer_sequence.png

从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);
            }
        }
    }
  1. 这两个方法最终其实都会调用到ViewRootImpl中的scheduleTraversals(),所不同的是invalidate()会指定dirty区域,dirty区域就是调用invalidate者对应view的区域,关于dirty区域后续再详述。
  2. 这里需要注意两个对象:
    。mParent: 这个是ViewParent类型,是个接口,ViewRootImpl实现了这个接口,在ViewRootImpl初始化的时候调用setView会把自己的引用传递给View
    。mAttachInfo:AttachInfo对象,是View的内部类,View都会附着到一个Window上面去,而这个mAttachInfo就包含了附着相关的一些信息
  3. 关于ViewRootImpl的信息会在介绍ViewRoot的时候再说,这里先看看View和ViewRootImpl类图关系


    View_class.png
//ViewRootImpl.java
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        }
    }
  1. mChoreographer: ViewRootImpl在初始化的时候初始化该对象,详见Choreography第一部分
  2. mTraversalScheduled:这个变量用来标志发起了view遍历请求,可以看到同一时间ViewRoot只能进行一个请求,其实也很好理解,这个只是请求,VSync回来之后才会进行view的遍历绘制,多个请求也没有意义。
  3. 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);
            }
        }
    }
  1. 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信号来临,就会通知对应的注册者。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。