android ui渲染分析器,Android应用程序UI硬件加速渲染的动画执行过程分析

RenderNode类的成员变量mAnimatorManager描述的是一个AnimatorManager对象。这个AnimatorManager对象用来管理一个RenderNode对象所关联的动画。因此,RenderNode类的成员函数addAnimator所做的事情就是将参数animator描述的动画保存在当前正在处理的RenderNode对象内部的一个AnimatorManager对象中,这是通过调用AnimatorManager类的成员函数addAnimator完成的。

这个函数定义在文件frameworks/base/libs/hwui/AnimatorMaager.cpp中。

在分析AnimatorManager类的成员函数addAnimator的实现之前,我们首先了解AnimatorManager类的三个成员变量:

1. mParent,它描述的是一个RenderNode对象,该RenderNode对象与当前正在处理的AnimatorManager对象关联。

2. mNewAnimators,它描述的是一个Vector,该Vector用来保存新增加的动画。

3. mAnimators,它描述的也是一个Vector。在绘制应用程序窗口的下一帧之前,新增加的动画会从成员变量mNewAnimators描述的Vector转移到成员变量mAnimators描述的Vector中去等待处理。

AnimatorManager类的成员函数addAnimator首先是增加参数animator描述的一个BaseRenderNodeAnimator对象的引用计数,因为后面要将它添加成员变量mNewAnimators描述的一个Vector中去。此外,AnimatorManager类的成员函数addAnimator还会调用参数animator描述的一个BaseRenderNodeAnimator对象的成员函数attach将该BaseRenderNodeAnimator对象与要显示动画的Render Node进行关联。

这一步执行完成之后,我们就将要显示的动画设置到目标View关联的一个RenderNode对象内部的一个AnimatorManager对象中去了。返回到Java层的RenderNode类的成员函数addAniamtor中,接下来我们继续分析ViewRootImpl类的成员函数registerAnimatingRenderNode的实现,以便可以了解Render Thread知道有Render Node有新的动画需要显示的过程。

ViewRootImpl类的成员函数registerAnimatingRenderNode的实现如下所示:

public final class ViewRootImpl implements ViewParent,

View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {

......

public void registerAnimatingRenderNode(RenderNode animator) {

if (mAttachInfo.mHardwareRenderer != null) {

mAttachInfo.mHardwareRenderer.registerAnimatingRenderNode(animator);

} else {

if (mAttachInfo.mPendingAnimatingRenderNodes == null) {

mAttachInfo.mPendingAnimatingRenderNodes = new ArrayList();

}

mAttachInfo.mPendingAnimatingRenderNodes.add(animator);

}

}

......

}

这个函数定义在文件frameworks/base/core/java/android/view/ViewRootImpl.java中。

当ViewRootImpl类的成员变量mAttachInfo指向的一个AttachInfo对象的成员变量mHardwareRenderer的值不等于null的时候,它指向的是一个ThreadedRenderer对象。在这种情况下,ViewRootImpl类的成员函数registerAnimatingRenderNode会直接调用该ThreadedRenderer对象的成员函数registerAnimatingRenderNode将参数animator描述的一个Render Node注册到Render Thread中去,以便Render Thread知道哪些Rendr Node有新的动画需要显示。

另一方面,当ViewRootImpl类的成员变量mAttachInfo指向的一个AttachInfo对象的成员变量mHardwareRenderer的值等于null的时候,这意味着应用程序窗口使用软件渲染或者使用硬件加速渲染但是硬件加速渲染环境还没有初始化好。在这两种情况下,都是先将参数animator描述的Render Node保存在成员变量mAttachInfo指向的一个AttachInfo对象的成员变量mPendingAnimatingRenderNodes描述的一个列表中等待处理。

从前面Android应用程序UI硬件加速渲染的Display List构建过程分析一文可以知道,当使用硬件加速渲染时,应用程序窗口的渲染是从调用ThreadedRenderer类的成员函数draw开始的,它的实现如下所示:

public class ThreadedRenderer extends HardwareRenderer {

......

@Override

void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {

......

updateRootDisplayList(view, callbacks);

......

if (attachInfo.mPendingAnimatingRenderNodes != null) {

final int count = attachInfo.mPendingAnimatingRenderNodes.size();

for (int i = 0; i < count; i++) {

registerAnimatingRenderNode(

attachInfo.mPendingAnimatingRenderNodes.get(i));

}

attachInfo.mPendingAnimatingRenderNodes.clear();

// We don't need this anymore as subsequent calls to

// ViewRootImpl#attachRenderNodeAnimator will go directly to us.

attachInfo.mPendingAnimatingRenderNodes = null;

}

int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,

recordDuration, view.getResources().getDisplayMetrics().density);

if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {

attachInfo.mViewRootImpl.invalidate();

}

}

......

}

这个函数定义在文件frameworks/base/core/java/android/view/ThreadedRenderer.java中。

ThreadedRenderer类的成员函数draw在调用成员函数updateRootDisplayList构建应用程序窗口的Display List之后,并且调用成员函数nSyncAndDrawFrame渲染应用程序窗口的Display List之前,会调用成员函数registerAnimatingRenderNode处理保存在上面提到的AttachInfo对象的成员变量mPendingAnimatingRenderNodes描述的一个列表中的每一个Render Node。

ThreadedRenderer类的成员函数registerAnimatingRenderNode的实现如下所示:

public class ThreadedRenderer extends HardwareRenderer {

......

@Override

void registerAnimatingRenderNode(RenderNode animator) {

nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode);

}

......

}

这个函数定义在文件frameworks/base/core/java/android/view/ThreadedRenderer.java中。

ThreadedRenderer类的成员函数registerAnimatingRenderNode调用另外一个成员函数nRegisterAnimatingRenderNode将参数animator描述的一个Render Node注册到Render Thread中去。

ThreadedRenderer类的成员函数nRegisterAnimatingRenderNode是一个JNI函数,由Native层的函数android_view_ThreadedRenderer_registerAnimatingRenderNode实现,如下所示:

static void android_view_ThreadedRenderer_registerAnimatingRenderNode(JNIEnv* env, jobject clazz,

jlong rootNodePtr, jlong animatingNodePtr) {

RootRenderNode* rootRenderNode = reinterpret_cast(rootNodePtr);

RenderNode* animatingNode = reinterpret_cast(animatingNodePtr);

rootRenderNode->attachAnimatingNode(animatingNode);

}

这个函数定义在文件frameworks/base/core/jni/android_view_ThreadedRenderer.cpp中。

参数rootNodePtr指向的是一个RootRenderNode对象,该RootRenderNode对象描述的是应用程序窗口的Root Render Node,这里主要就是将参数animatorNodePtr描述的一个Render Node注册在上述的RootRenderNode对象的内部,这是通过调用RootRenderNode类的成员函数attachAnimatingNode实现的。

RootRenderNode类的成员函数attachAnimatingNode的实现如下所示:

class RootRenderNode : public RenderNode, ErrorHandler {

public:

......

void attachAnimatingNode(RenderNode* animatingNode) {

mPendingAnimatingRenderNodes.push_back(animatingNode);

}

......

private:

......

std::vector< sp > mPendingAnimatingRenderNodes;

};

这个函数定义在文件frameworks/base/core/jni/android_view_ThreadedRenderer.cpp中。

RootRenderNode类的成员函数attachAnimatingNode将参数animatingNode描述的一个Render Node保存成员变量mPendingAnimatingRenderNodes描述的一个Vector中。保在这个Vector中的Render Node将会在应用程序窗口的下一帧被渲染时得到处理。

从前面Android应用程序UI硬件加速渲染的Display List渲染过程分析一文可以知道,Render Thread在渲染应用程序窗口的下一帧时,会调用CanvasContext类的成员函数prepareTree将应用程序窗口的Display List从Main Thread同步到Render Thread,如下所示:

void CanvasContext::prepareTree(TreeInfo& info) {

......

info.renderer = mCanvas;

......

mAnimationContext->startFrame(info.mode);

mRootRenderNode->prepareTree(info);

mAnimationContext->runRemainingAnimations(info);

......

int runningBehind = 0;

// TODO: This query is moderately expensive, investigate adding some sort

// of fast-path based off when we last called eglSwapBuffers() as well as

// last vsync time. Or something.

mNativeWindow->query(mNativeWindow.get(),

NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind);

info.out.canDrawThisFrame = !runningBehind;

if (info.out.hasAnimations || !info.out.canDrawThisFrame) {

if (!info.out.requiresUiRedraw) {

// If animationsNeedsRedraw is set don't bother posting for an RT anim

// as we will just end up fighting the UI thread.

mRenderThread.postFrameCallback(this);

}

}

}

这个函数定义定义在文件frameworks/base/libs/hwui/renderthread/CanvasContext.cpp中。

CanvasContext类的成员函数prepareTree的详细实现分析可以参考前面Android应用程序UI硬件加速渲染的Display List渲染过程分析一文,这里我们主要关注与动画相关的两个操作:

1. 第一个操作是在调用RenderNode类的成员函数prepareTree同步应用程序窗口的Display List之前,调用成员变量mAnimationContext描述的一个AnimationContext对象的成员函数startFrame执行一些动画显示的准备工作。

2. 第二个操作是在调用RenderNode类的成员函数prepareTree同步应用程序窗口的Display List之后,调用成员变量mAnimationContext描述的一个AnimationContext对象的成员函数runRemainingAnimations更新剩下的还未完成的动画。

接下来我们就分别分析这两个操作的执行过程,即分析AnimationContext类的成员函数startFrame和runRemainingAnimations的实现。不过,在分析这两个函数的实现之前,我们首先要了解CanvasContext类的成员变量mAnimationContext的初始化过程。

从前面Android应用程序UI硬件加速渲染环境初始化过程分析一文可以知道,在Android应用程序的硬件加速渲染环境的初始化过程中,会创建一个RenderProxy对象,如下所示:

static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz,

jboolean translucent, jlong rootRenderNodePtr) {

RootRenderNode* rootRenderNode = reinterpret_cast(rootRenderNodePtr);

ContextFactoryImpl factory(rootRenderNode);

return (jlong) new RenderProxy(translucent, rootRenderNode, &factory);

}

这个函数定义在文件frameworks/base/core/jni/android_view_ThreadedRenderer.cpp中。

在调用RenderProxy类的构造函数创建一个RenderProxy对象的时候,传递进去的第三个参数是一个ContextFactoryImpl对象。

我们继续看RenderProxy类的构造函数的实现,如下所示:

CREATE_BRIDGE4(createContext, RenderThread* thread, bool translucent,

RenderNode* rootRenderNode, IContextFactory* contextFactory) {

return new CanvasContext(*args->thread, args->translucent,

args->rootRenderNode, args->contextFactory);

}

RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory)

: mRenderThread(RenderThread::getInstance())

, mContext(0) {

SETUP_TASK(createContext);

args->translucent = translucent;

args->rootRenderNode = rootRenderNode;

args->thread = &mRenderThread;

args->contextFactory = contextFactory;

mContext = (CanvasContext*) postAndWait(task);

mDrawFrameTask.setContext(&mRenderThread, mContext);

}

这个函数定义在文件frameworks/base/libs/hwui/renderthread/RenderProxy.cpp中。

RenderProxy类的构造函数首先是向Render Thread的Task Queue发送一个Task,并且等待该Task执行完成。上述Task在执行的时候,会调用由宏CREATE_BRIDGE4声明的函数createContext。该函数所做的事情就是创建一个CanvasContext对象。该CanvasContext对象最终保存在RenderProxy类的成员变量mContext中。

在调用CanvasContext类的构造函数创建一个CanvasContext对象的时候,传递进去的第四个参数就是在前面分析的函数android_view_ThreadedRenderer_createProxy声明的一个ContextFactoryImpl对象。

CanvasContext类的构造函数的实现如下所示:

CanvasContext::CanvasContext(RenderThread& thread, bool translucent,

RenderNode* rootRenderNode, IContextFactory* contextFactory)

:...... {

mAnimationContext = contextFactory->createAnimationContext(mRenderThread.timeLord());

......

}

这个函数定义在文件frameworks/base/libs/hwui/renderthread/CanvasContext.cpp中。

从这里就可以看出,CanvasContext的成员变量mAnimationContext指向的一个AnimationContext对象是由参数contextFactory描述的一个IContextFactory接口的成员函数createAnimationContext创建的。

从前面的调用过程可以知道,参数contextFactory指向的实际上是一个ContextFactoryImpl对象,它的成员函数createAnimationContext的实现如下所示:

class ContextFactoryImpl : public IContextFactory {

public:

ContextFactoryImpl(RootRenderNode* rootNode) : mRootNode(rootNode) {}

virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) {

return new AnimationContextBridge(clock, mRootNode);

}

private:

RootRenderNode* mRootNode;

};

这个函数定义在文件frameworks/base/core/jni/android_view_ThreadedRenderer.cpp中。

ContextFactoryImpl类的成员函数createAnimationContext创建的是一个AnimationContextBridge对象,由此就可见,CanvasContext的成员变量mAnimationContext实际指向的一个AnimationContextBridge对象。

明白了这一点之后,回到前面分析的CanvasContext类的成员函数prepareTree中,它在同步应用程序窗口的Display List之前,调用了AnimationContextBridge类的成员函数startFrame执行一些动画显示的准备工作。

AnimationContextBridge类的成员函数startFrame的实现如下所示:

class AnimationContextBridge : public AnimationContext {

public:

......

// Marks the start of a frame, which will update the frame time and move all

// next frame animations into the current frame

virtual void startFrame(TreeInfo::TraversalMode mode) {

if (mode == TreeInfo::MODE_FULL) {

mRootNode->doAttachAnimatingNodes(this);

}

AnimationContext::startFrame(mode);

}

......

private:

sp mRootNode;

......

};

这个函数定义在文件frameworks/base/core/jni/android_view_ThreadedRenderer.cpp中。

参数mode的值等于TreeInfo::MODE_FULL,表示目前Render Thread是处于同步应用程序窗口的Display List的过程中。在这种情况下,AnimationContextBridge类的成员函数startFrame执行两个操作:

1. 调用成员变量mRootNode描述的一个RootRenderNode对象的成员函数doAttachAnimatingNodes处理它内部保存的有动画显示的Render Node。

2. 调用父类AnimationContext的成员函数startFrame继续执行一些动画显示之前的准备工作。

接下来,我们就先分析RootRenderNode类的成员函数doAttachAnimatingNodes的实现,再分析AnimationContext类的成员函数startFrame的实现。

RootRenderNode类的成员函数doAttachAnimatingNodes的实现如下所示:

class RootRenderNode : public RenderNode, ErrorHandler {

public:

......

void doAttachAnimatingNodes(AnimationContext* context) {

for (size_t i = 0; i < mPendingAnimatingRenderNodes.size(); i++) {

RenderNode* node = mPendingAnimatingRenderNodes[i].get();

context->addAnimatingRenderNode(*node);

}

mPendingAnimatingRenderNodes.clear();

}

private:

......

std::vector< sp > mPendingAnimatingRenderNodes;

};

这个函数定义在文件frameworks/base/core/jni/android_view_ThreadedRenderer.cpp中。

RootRenderNode类的成员函数doAttachAnimatingNodes遍历保存在成员变量mPendingAnimatingRenderNodes描述的一个Vector中的每一个RenderNode对象,并且分别调用参数context描述的一个AnimationContextBridge对象的成员函数addAnimatingRenderNode对它们进行处理。

AnimationContextBridge类的成员函数addAnimatingRenderNode是从父类AnimationContext继承下来的,它的实现如下所示:

void AnimationContext::addAnimatingRenderNode(RenderNode& node) {

if (!node.animators().hasAnimationHandle()) {

AnimationHandle* handle = new AnimationHandle(node, *this);

addAnimationHandle(handle);

}

}

这个函数定义在文件frameworks/base/libs/hwui/AnimationContext.cpp中。

参数node指向的是一个RenderNode对象,调用它的成员函数animators可以获得它内部的一个AnimatorManager对象。如果该AnimatorManager对象还没有设置过一个AnimationHandle对象,那么AnimationContext类的成员函数addAnimatingRenderNode就为其设置一个AnimationHandle对象,并且这个AnimationHandle对象会通过AnimationContext类的成员函数addAnimationHandle保存在当前正在处理的一个AnimationContext对象的内部。

AnimationContext类的成员函数addAnimationHandle的实现如下所示:

void AnimationContext::addAnimationHandle(AnimationHandle* handle) {

handle->insertAfter(&mNextFrameAnimations);

}

这个函数定义在文件frameworks/base/libs/hwui/AnimationContext.cpp中。

AnimationContext类的成员函数addAnimationHandle所做的事情就是将参数handle描述的一个AnimationHandle对象插入成员变量mNextFrameAnimations描述的一个AnimationHandle列表中。

由此我们就可以推断出,只要AnimationContext类的成员变量NextFrameAnimations描述的一个AnimationHandle列表不为空,那么就意味着Render Thread在渲染应用程序窗口的下一帧的时候,有Render Node需要显示动画。

这一步执先完成之后,返回到AnimationContextBridge类的成员函数startFrame中,接下来它所做的事情就是调用父类AnimationContext的成员函数startFrame继续执行一些动画显示之前的准备工作。

AnimationContext的成员函数startFrame的实现如下所示:

void AnimationContext::startFrame(TreeInfo::TraversalMode mode) {

......

AnimationHandle* head = mNextFrameAnimations.mNextHandle;

if (head) {

mNextFrameAnimations.mNextHandle = NULL;

mCurrentFrameAnimations.mNextHandle = head;

head->mPreviousHandle = &mCurrentFrameAnimations;

}

......

}

这个函数定义在文件frameworks/base/libs/hwui/AnimationContext.cpp中。

AnimationContext的成员函数startFrame所做的事情就是将成员变量mNextFrameAnimations描述的一个AnimationHandle列表转移到另外一个成员变量mCurrentFrameAnimations中。

由此我们就可以推断出,只要AnimationContext类的成员变量mCurrentFrameAnimations描述的一个AnimationHandle列表不为空,那么就意味着Render Thread在渲染应用程序窗口的当前帧的时候,有Render Node需要显示动画。

这一步执行完成之后,返回到CanvasContext类的成员函数prepareTree中,当它同步同步应用程序窗口的Display List之后,就调用成员变量mAnimationContext描述的一个AnimationContextBridge对象的成员函数runRemainingAnimations更新剩下的还未完成的动画。

AnimationContextBridge类的成员函数runRemainingAnimations的实现如下所示:

class AnimationContextBridge : public AnimationContext {

public:

......

// Runs any animations still left in mCurrentFrameAnimations

virtual void runRemainingAnimations(TreeInfo& info) {

AnimationContext::runRemainingAnimations(info);

......

}

......

};

这个函数定义在文件frameworks/base/core/jni/android_view_ThreadedRenderer.cpp中。

AnimationContextBridge类的成员函数runRemainingAnimations主要是通过调用父类AnimationContext的成员函数runRemainingAnimations更新剩下的还未完成的动画。

AnimationContext类的成员函数runRemainingAnimations的实现如下所示:

void AnimationContext::runRemainingAnimations(TreeInfo& info) {

while (mCurrentFrameAnimations.mNextHandle) {

AnimationHandle* current = mCurrentFrameAnimations.mNextHandle;

AnimatorManager& animators = current->mRenderNode->animators();

animators.pushStaging();

animators.animateNoDamage(info);

......

}

}

这个函数定义在文件frameworks/base/libs/hwui/AnimationContext.cpp中。

前面提到,应用程序窗口当前帧要显示动画都记录在AnimationContext类的成员mCurrentFrameAnimations描述的一个AnimationHandle列表中。因此,AnimationContext类的成员函数runRemainingAnimations就遍历这个列表中的每一个AnimationHandle,并且获得与其关联的一个AnimatorManager。有了这些AnimatorManager之的,就可以调用它们的成员函数pushStaging和animateNoDamage来执行动画,其实就是计算动画的下一帧参数,以便应用在目标Render Node上。

AnimatorManager类的成员函数pushStaging的实现如下所示:

void AnimatorManager::pushStaging() {

if (mNewAnimators.size()) {

......

move_all(mNewAnimators, mAnimators);

}

for (vector::iterator it = mAnimators.begin(); it != mAnimators.end(); it++) {

(*it)->pushStaging(mAnimationHandle->context());

}

}

这个函数定义在文件frameworks/base/libs/hwui/AnimatorManager.cpp中。

从前面的分析可以知道,一开始的时候,应用程序窗口新增加的动画都保存在AnimatorManager类的成员变量mNewAnimators描述的一个Vector中,这里将它们移动至AnimatorManager类的另外一个成员变量mAnimators中,类似于我们在前面Android应用程序UI硬件加速渲染的Display List渲染过程分析一文提到的将Display List从Main Thread同步到Render Thread一样。

最后,AnimatorManager类的成员函数pushStaging遍历已经移动至新列表中的每一个动画,并且调用它们的成员函数pushStaging,用来同步它们的开始和结束状态,也就是检查动画是否已经被start或者已经end了。如果已经被start,那么就执行一些动画开始执行前的准备工作,例如计算动画的开始时间。如果已经end,就发出事件通知给侦听者。

这一步执先完成之的,回到前面分析的AnimationContext类的成员函数runRemainingAnimations中,接下来就调用AniamtorManager类的成员函数animateNoDamage执行动画,它的实现如下所示:

void AnimatorManager::animateNoDamage(TreeInfo& info) {

if (!mAnimators.size()) return;

animateCommon(info);

}

这个函数定义在文件frameworks/base/libs/hwui/AnimatorManager.cpp中。

AniamtorManager类的成员函数animateNoDamage通过调用另外一个成员函数animateCommon来执行当前正在处理的AnimatorManager对象关联的动画,也就是某一个Render Node关联的动画。

AniamtorManager类的成员函数animateCommon的实现如下所示:

uint32_t AnimatorManager::animateCommon(TreeInfo& info) {

AnimateFunctor functor(info, mAnimationHandle->context());

std::vector< BaseRenderNodeAnimator* >::iterator newEnd;

newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);

mAnimators.erase(newEnd, mAnimators.end());

mAnimationHandle->notifyAnimationsRan();

return functor.dirtyMask;

}

这个函数定义在文件frameworks/base/libs/hwui/AnimatorManager.cpp中。

前面提到,当前正在处理的AnimatorManager对象关联的动画都保存其成员变量mAnimators描述的一个Vector,因此这里就会通过函数std::remove_if来遍历这些动画,并且对于每一个动画,都通过本地变量functor描述的一个AnimatorFunctor对象的操作符重载函数()来执行它的当前帧。

AnimatorFunctor类的操作符重载函数()执行完成动画的当前帧之后,如果动画已经完成,即没有下一帧了,那么它就会返回一个true值给调用者,这样会导致函数std::remove_if将该动画移动至列表的末尾位置。

AnimatorFunctor类的操作符重载函数()的实现如下所示:

class AnimateFunctor {

public:

AnimateFunctor(TreeInfo& info, AnimationContext& context)

: dirtyMask(0), mInfo(info), mContext(context) {}

bool operator() (BaseRenderNodeAnimator* animator) {

dirtyMask |= animator->dirtyMask();

bool remove = animator->animate(mContext);

if (remove) {

animator->decStrong(0);

} else {

if (animator->isRunning()) {

mInfo.out.hasAnimations = true;

}

if (CC_UNLIKELY(!animator->mayRunAsync())) {

mInfo.out.requiresUiRedraw = true;

}

}

return remove;

}

uint32_t dirtyMask;

private:

TreeInfo& mInfo;

AnimationContext& mContext;

};

这个函数定义在文件frameworks/base/libs/hwui/AnimatorManager.cpp中。

AnimatorFunctor类的操作符重载函数()主要就是调用参数animator指向的一个BaseRenderNodeAnimator对象的成员函数animate来执行该BaseRenderNodeAnimator对象所描述的动画的当前帧。

当BaseRenderNodeAnimator类的成员函数animate的返回值等于true的时候,就表示参数animator描述的动画已经显示结束了,这意味着它可以从我们上面描述的动画列表中删除。

另一方面,当BaseRenderNodeAnimator类的成员函数animate的返回值等于false的时候,就表示参数animator描述的动画还没有显示完成。这时候如果该动画没有被中途停止,即调用参数animator指向的一个BaseRenderNodeAnimator对象的成员函数isRunning的返回值等于true,那么就会将当前正在处理的AnimatorFunctor对象的成员变量mInfo指向的一个TreeInfo对象的成员变量out描述的一个Out结构体的成员变量hasAnimations的值设置为true。这样做的作用是什么呢?

我们首先梳理一下Render Thread目前所处的位置。目前Render Thread正处于将Main Thread的Display List同步到Render Thread的过程中,只不过目前正在处理的动画相关的操作。Render Thead在执行这个同步过程之前,会构造一个TreeInfo对象,这一点可以参考前面Android应用程序UI硬件加速渲染的Display List渲染过程分析一文分析的DrawFrameTask类的成员函数run。DrawFrameTask类的成员函数run会将该TreeInfo对象传递给接下来要调用的函数。AnimatorFunctor类的操作符重载函数()就是被调用的其中一个函数,并且它的成员变量mInfo指向的TreeInfo对象就上述在DrawFrameTask类的成员函数run构造的TreeInfo对象。

通过将这个TreeInfo对象的成员变量out描述的一个Out结构体的成员变量hasAnimations的值,就可以让Render Thread通知应用程序窗口的下一帧是否还有动画需要显示。再结合上述TreeInfo对象的成员变量out描述的一个Out结构体的另外一个成员变量requiresUiRedraw的值,Render Thread就可以知道它是自动执行那些未完成的动画,还是等待Main Thread通知它执行。

当参数animator指向的一个BaseRenderNodeAnimator对象描述的是一个同步动画时,那么调用它的成员函数mayRunAsync的返回值就等于false,这时候上述TreeInfo对象的成员变量out描述的一个Out结构体的成员变量requiresUiRedraw的值就会被设置为true,这将导致未完成的动画要由Main Thread通知Render Thread来执行。这个逻辑同时也意味着只有当所有未完成的动画都是异步动画时,Render Thread才可以自动执行它们。这个自动执行未完成的异步动画的过程我们后面再详细分析。

这一步执行完成之后,返回到前面分析的AniamtorManager类的成员函数animateCommon,也就是函数std::remove_if执行完毕的位置。函数std::remove_if执行完毕,会返回一个iterator。这个iterator指向的是被移动至列表末尾的第一个动画。这意味着从这个iterator开始,到列表的结束,保存的动画都是已经执行完成了的,因此就可以将它们从列表中删除。

最后,AniamtorManager类的成员函数animateCommon调用成员变量mAnimationHandle指向的一个AnimationHandle对象的成员函数notifyAnimationsRan,用来发送一个动画帧执先完成的通知。从上面的分析可以知道,这个AnimationHandle对象是在添加一个新的动画添到Render Thread时创建并且设置给关联的AnimatorManager对象的,具体可以参数前面分析的AnimationContext类的成员函数addAnimatingRenderNode的实现。

AnimationHandle类的成员函数notifyAnimationsRan的实现如下所示:

void AnimationHandle::notifyAnimationsRan() {

removeFromList();

if (mRenderNode->animators().hasAnimators()) {

mContext.addAnimationHandle(this);

} else {

release();

}

}

这个函数定义在文件frameworks/base/libs/hwui/AnimationContext.cpp中。

AnimationHandle类的成员函数notifyAnimationsRan首先是调用成员函数removeFromList将当前正处理的一个AnimationHandle对象从所在的列表中移除。回忆前面的分析,当前正处理的一个AnimationHandle对象位于的列表正是AnimationContext类的成员变量mCurrentFrameAnimations描述的一个AnimationHandle列表。

将当前正处理的一个AnimationHandle对象从所在的列表中移除之后,AnimationHandle类的成员函数notifyAnimationsRan再判断它所关联的Render Node是否还有未执行完成的动画。如果有的话,那么就会调用成员变量mContext描述的一个AnimationContext对象的成员函数addAnimationHandle将当前正处理的一个AnimationHandle对象重新添加到另外一个列表去。

从前面的分析可以知道,AnimationContext类的成员函数addAnimationHandle会将指定的AnimationContext对象添加到其成员变量mNextFrameAnimations描述的一个列表中。又从前面分析的AnimationContext类的成员函数startFrame可以知道,保存在AnimationContext类的成员变量mNextFrameAnimations描述的列表中的AnimationContext对象在应用程序窗口动画显示之前,会被移动至AnimationContext类的成员变量mCurrentFrameAnimations描述的另一个列表中。

这意味动画的执行过程如下所示:

1. 在应用程序窗口每一帧的渲染过程中,如果需要显示一个动画,那么就需要先将一个AnimationContext对象添加到AnimationContext类的成员变量mNextFrameAnimations描述的列表中。

2. 当一个动画需要执行一帧时,与它关联的AnimationContext对象将会AnimationContext类的成员变量mNextFrameAnimations描述的列表转移至成员变量mCurrentFrameAnimations描述的另外一个列表。

3. 当一个动画的一帧执行完成时,与它关联的AnimationContext对象又会从AnimationContext类的成员变量mCurrentFrameAnimations描述的列表移除。

4. 当一个动画的一帧执行完成时,如果整个动画还未执行完成,那么它关联的AnimationContext对象又会重新添加到AnimationContext类的成员变量mNextFrameAnimations描述的列表中。接着下来又重复执行前面的第1步。

另一方面,如果一个Render Node关联的所有动画均已执行完毕,那么AnimationHandle类的成员函数notifyAnimationsRan会调用另外一个成员函数release将它内部的一个AnimatorManager对象关联的一个AnimationHandle对象移除。这意味着下次我们再为该Render Node时,需要重新为它创建和关联一个新的AnimationHandle对象,如前面分析的AnimationContext类的成员函数addAnimatingRenderNode所示。

这样在应用程序窗口每一个帧的渲染过程中涉及到的动画的执行过程我们就分析完毕。注意,这个动画执行过程是在Main Thread和Render Thread完全同步的条件下执行的,并且这里说的动画执行,只是计算出动画对目标Render Node的属性影响。例如,计算出动画对目标Render Node在X轴和Y轴的位置。新计算出来的属性将会在目标Render Node的Display List的绘制命令转化为Open GL命令执行时得到应用,从而就完成一个动画帧的显示。

理解了动画的正常执行过程之后,也就是由Main Thread驱动Render Thread执行的过程,我们再来看Render Thread在不需要Main Thread干预的情况下自动执行动画的过程。在分析之前,我们首先理解一下前面提到的同步动画和异步动画的概念。

从前面的分析可以知道,如果我们使用Render Thread来计算和执行动画,那么动画就会被封装成一个RenderNodeAnimator对象,如前面分析的ViewPropertyAnimatorRT类的成员函数doStartAnimation所示。

RenderNodeAnimator类有一个成员函数setAllowRunningAsynchronously,允许在一个动画执行之前,设置为是否可以异步执行,如下所示:

public class RenderNodeAnimator extends Animator {

......

@Override

public void setAllowRunningAsynchronously(boolean mayRunAsync) {

checkMutable();

nSetAllowRunningAsync(mNativePtr.get(), mayRunAsync);

}

......

}

这个函数定义在文件frameworks/base/core/java/android/view/RenderNodeAnimator.java中。

当参数mayRunAsync的值等于true时,就表示将一个动画设置为异步动画;否则的话,就设置为同步动画。这个信息会通过调用RenderNodeAnimator类的另外一个成员函数nSetAllowRunningAsync同步到Native层关联的同样是用来描述动画的一个BaseRenderNodeAnimator对象中去。

RenderNodeAnimator类的成员函数nSetAllowRunningAsync是一个JNI函数,由Native层的函数setAllowRunningAsync实现,如下所示:

static void setAllowRunningAsync(JNIEnv* env, jobject clazz, jlong animatorPtr, jboolean mayRunAsync) {

BaseRenderNodeAnimator* animator = reinterpret_cast(animatorPtr);

animator->setAllowRunningAsync(mayRunAsync);

}

这个函数定义在文件frameworks/base/core/jni/android_view_RenderNodeAnimator.cpp中。

参数animatorPtr描述的就是Native用来描述动画的一个BaseRenderNodeAnimator对象,这里调用它的成员函数setAllowRunningAsync设置它是一个同步动画还是一个异步动画。

BaseRenderNodeAnimator类的setAllowRunningAsync的实现如下所示:

class BaseRenderNodeAnimator : public VirtualLightRefBase {

......

public:

......

ANDROID_API void setAllowRunningAsync(bool mayRunAsync) {

mMayRunAsync = mayRunAsync;

}

bool mayRunAsync() { return mMayRunAsync; }

......

};

这两个函数定义在文件frameworks/base/libs/hwui/Animator.h中。

BaseRenderNodeAnimator类的setAllowRunningAsync将动画的同步异步信息记录在成员变量mMayRunAsync中。这样就可以通过调用另外一个成员函数mayRunAsync就可以知道一个动画是同步的还是异步,如前面分析的AnimatorFunctor类的操作符重载函数()所示。

了解了一个动画的同步异步概念之后,回到前面分析的CanvasContext类的成员函数prepareTree中,当它同步完成应用程序窗口的Display List以及处理过应用程序窗口的动画之后,如果应用程序窗口还有未完成的动画,并且这些都是异步动画,那么就会注册一个IFrameCallback接口到Render Thread中。为了方便描述,我们重新将这部分代码列出来,如下所示:

void CanvasContext::prepareTree(TreeInfo& info) {

......

info.renderer = mCanvas;

......

mAnimationContext->startFrame(info.mode);

mRootRenderNode->prepareTree(info);

mAnimationContext->runRemainingAnimations(info);

......

if (info.out.hasAnimations || !info.out.canDrawThisFrame) {

if (!info.out.requiresUiRedraw) {

// If animationsNeedsRedraw is set don't bother posting for an RT anim

// as we will just end up fighting the UI thread.

mRenderThread.postFrameCallback(this);

}

}

}

这个函数定义在文件frameworks/base/libs/hwui/renderthread/CanvasContext.cpp中。

根据我们前面的分析,当应用程序窗口还有未完成的动画时,参数info指向的一个TreeInfo对象的成员变量out指向的一个Out结构体的成员变量hasAnimations的值就等于true,而当这些未完成的动画都是异步动画时,上述的Out结构体的成员变量requiresUiRedraw的值就等于false。在这种情况下,CanvasContext类的成员函数prepareTree就会注册一个IFrameCallback接口到Render Thread中。这个注册过程可以参考前面Android应用程序UI硬件加速渲染环境初始化过程分析一文。

上面注册的IFrameCallback接口CanvasContext类实现,从前面Android应用程序UI硬件加速渲染环境初始化过程分析一文可以知道,当下一个Vsync信号到来的时候,Render Thread就会调用CanvasContext类的成员函数doFrame。

CanvasContext类的成员函数doFrame的实现如下所示:

void CanvasContext::doFrame() {

......

TreeInfo info(TreeInfo::MODE_RT_ONLY, mRenderThread.renderState());

prepareTree(info);

if (info.out.canDrawThisFrame) {

draw();

}

}

这个函数定义在文件frameworks/base/libs/hwui/renderthread/CanvasContext.cpp中。

CanvasContext类的成员函数doFrame首先是构造一个mode值等于TreeInfo::MODE_RT_ONLY的TreeInfo对象,接着再使用这个TreeInfo对象来调用我们前面分析过的成员函数prepareTree。从前面Android应用程序UI硬件加速渲染的Display List渲染过程分析一文可以知道,当传递给anvasContext类的成员函数prepareTree的TreeInfo对象的mode值等于TreeInfo::MODE_RT_ONLY时,它就仅仅会执行动画相关的操作,以及更新设置了Layer的Render Node的操作,而不会执行同步应用程序窗口的Display List的操作。

执行完成动画相关的操作之后,CanvasContext类的成员函数doFrame接下来在允许绘制应用程序窗口下一帧的条件下,也就是在Surface Flinger不是太忙的时候,就会调用另外一个成员函数draw渲染应用程序窗口的Display List,也就是使用Open GL命令来渲染应用程序窗口的UI,并且将得到的图形缓冲区提交给Surface Flinger进行合成以及显示在屏幕上。

注意,前面在调用CanvasContext类的成员函数prepareTree的过程中,如果那些未完成的异步动画还未执行完成,那么它又会继续向Render Thread注册一个IFrameCallback接口,这样就会使得下一个Vsync信号到来的时候,CanvasContext类的成员函数doFrame又会被调用。这个过程直至所有的异步动画都执行完成为止。这样就使得Render Thread可以在没有Main Thread干预的条件下自动执行动画。

这样,Android在动画显示过程中的两个优化点都分析完成了,从中我们就可以看到Render Thread对提高动画流畅性的贡献。至些,Android应用程序UI硬件加速渲染技术这个系列的文章我们就全部学习完成了。要重新学习,请参考前面Android应用程序UI硬件加速渲染技术简要介绍和学习计划一文。更多的信息也可以关注老罗的新浪微博:https://weibo.com/shengyangluo。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值