关闭

Android 7.1 GUI系统-窗口管理WMS-动画的执行(七)

标签: 动画的执行stepAnimationstepAnimationLockedanimateLockedscheduleAnimationLoc
42人阅读 评论(0) 收藏 举报
分类:

前面只是动画资源的加载过程,下面看下动画是怎么执行起来的?

前面在分析窗口申请的过程中,分析过relayoutWindow中的调用performSurfacePlacement在这个函数的最后调用了mService.scheduleAnimationLocked(),来安排动画的执行。


void scheduleAnimationLocked() @WindowManagerService.java{
        if (!mAnimationScheduled) {
            mAnimationScheduled = true;
//通过Choreographer设置一个触发源,mChoreographer 是通过ThreadLocal保存的,所以它是一个线程中的单实例。
            mChoreographer.postFrameCallback(mAnimator.mAnimationFrameCallback);
        }
    }	

mAnimationScheduledtrue,表示当前正在scheduleanimantion,在mAnimationFrameCallback的回调中会把mAnimationScheduled再次置为false

Choreographer设置的动画的触发源是什么?这样看下Choreographer这个类的主要功能是什么:Choreographer会接从显示系统接收定时脉冲(如Vsync),然后安排渲染下一个显示帧的工作。动画的触发源就是Vsync

在动画框架或view层次中,应用程序通常使用较高的抽象跟Choreography间接交互,如:使用android.animation.ValueAnimator#start方法,post一个动画与渲染帧同步处理。

使用View#postOnAnimation方法,post一个Runnable,让其在下一个显示帧开始时调用。


有些情况,可能需要直接使用choreography的函数,如:

如果应用程序想在不同的线程里做渲染,可能是用GL,或者不使用animation框架、View层级,又要确保跟显示同步,这时可以使用Choreographer#postFrameCallback


Choreography一方面接收VSYNC信号,另一方面把这一事件转发给感兴趣的人,所有希望监听VSYNC信号的对象都要在Choreography中注册。

scheduleAnimationLocked中调用的是postFrameCallback,然后直接调用了postFrameCallbackDelayed


public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) @Choreographer.java{
        postCallbackDelayedInternal(CALLBACK_ANIMATION,
                callback, FRAME_CALLBACK_TOKEN, delayMillis);
    }

这里的CALLBACK_ANIMATION是回调类型,Choreography将注册者分为三个类型:CALLBACK_INPUTCALLBACK_ANIMATIONCALLBACK_TRAVERSAL(处理layoutdraw)。

注册的回调都放在一个数组mCallbackQueues中。


Vsync信号产生后,Choreography会通过doCallbacks,进一步调用到相应注册对象的doFrame函数。

这里回调的是WindowAnimator.java中的doFrame

WindowAnimator.java
        mAnimationFrameCallback = new Choreographer.FrameCallback() {
            public void doFrame(long frameTimeNs) {
                synchronized (mService.mWindowMap) {
                    mService.mAnimationScheduled = false;
                    animateLocked(frameTimeNs);
                }
            }
        };

通过animateLocked,各种动画开始单步执行。

private void animateLocked(long frameTimeNs) {
//当前时间。
	mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
//记录上一次的动画状态,判断动画是否结束。
	boolean wasAnimating = mAnimating;
//先本地记录对surface的更改,最后统一统计给surfaceflinger。
	SurfaceControl.openTransaction();
	SurfaceControl.setAnimationTransaction();

	try {
		final int numDisplays = mDisplayContentsAnimators.size();
//循环处理每个显示屏中的动画。
		for (int i = 0; i < numDisplays; i++) {
			final int displayId = mDisplayContentsAnimators.keyAt(i);
//执行appTransition中设置的appWindow动画,
			updateAppWindowsLocked(displayId);
//执行屏幕旋转动画,比如屏幕的横竖屏。
			final ScreenRotationAnimation screenRotationAnimation 
				=displayAnimator.mScreenRotationAnimation;
			if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
				if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) {
//动画没有结束,通过setAnimating把mAnimating设置为true。
					setAnimating(true);
				}else{
//动画结束了。
					…...
				}
			}
//更新每个所有应用中的动画,包括与退出、移除app相关的。这里会执行WindowStateAnimator动画。
			updateWindowsLocked(displayId);
			updateWallpaperLocked(displayId);


			final WindowList windows = mService.getWindowListLocked(displayId);
			final int N = windows.size();
			for (int j = 0; j < N; j++) {
//更新surface。
				windows.get(j).mWinAnimator.prepareSurfaceLocked(true);
			}
		}
//动画还没结束,再次调用 scheduleAnimationLocked。
		if (mAnimating) {
			mService.scheduleAnimationLocked();
		}
	}finally{
//统一提交给surfaceflinger处理。
		SurfaceControl.closeTransaction();
	}

//在执行动画最后一步step时, mAnimating为false, wasAnimating记录是上一次mAnimating 的值,所以为true,这里将请求一次遍历,计算窗口大小,performsurface等。
	if (!mAnimating && wasAnimating) {
		mWindowPlacerLocked.requestTraversal();
	}
}
	

不管那类动画,要更新动画调用的都是stepAnimationLocked,指定动画的单步,就是每个特定的时间计算动画的最新状态。如果函数true,说明动画还在进行,否则返回false

boolean stepAnimationLocked(long currentTime) @WindowStateAnimator.java{
//mWasAnimating 保存上一次的状态,通过比较mWasAnimating 和 isAnimationSet(),就知道动画是刚刚开始,还是停止了。	mWasAnimating = mAnimating;
//第一次执行动画,需要做些初始化。
	if (!mLocalAnimating) {
		mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
			displayInfo.appWidth, displayInfo.appHeight);
		mAnimDx = displayInfo.appWidth;
		mAnimDy = displayInfo.appHeight;
		mAnimation.setStartTime(mAnimationStartTime != -1
			? mAnimationStartTime : currentTime);
//已经执行过一次, mLocalAnimating置为true。
		mLocalAnimating = true;
//表示当前正在执行动画。
		mAnimating = true;
	}

// mAnimation做非null判断,因为不是每个WindowStateAnimator当前都有动画在执行。
	if ((mAnimation != null) && mLocalAnimating) {
		mLastAnimationTime = currentTime;
//执行一次单步,计算当前的动画状态,返回true,表示动画还没结束。
		if (stepAnimation(currentTime)) {
			return true;
		}
	}
}

如何执行一个单步。

private boolean stepAnimation(long currentTime) @WindowStateAnimator.java{
	currentTime = getAnimationFrameTime(mAnimation, currentTime);
	mTransformation.clear();
	final boolean more = mAnimation.getTransformation(currentTime, mTransformation);
	return more;
}

上面的函数会根据mAnimation设置的开始时间,结合当前时间,计算出动画的新的变换值,动画的四个要素是平移、缩放、旋转、透明度,将会根据设置的属性分别调用相应类型的applyTransformation,计算变换值,保存在mTransformation

中,其中平移、缩放、旋转由mMatrix表示,透明度由mAlpha表示。


完成动画数据的计算,接着就是真正显示到屏幕上,先由WMSsurface做更新,具体就是prepareSurfaceLocked的调用。

最后通过SurfaceControl.closeTransaction()关闭业务,将surface中的更新信息统一传给SurfaceFlinger,然后写入到framebuffer中,完成显示。



0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

Android系统窗口管理机制简介

一、概述 Android系统窗口管理是由WindowManagerService负责实现的.WindowManagerService(后面简称WMS)的代码位于 frameworks/base/ser...
  • qq_31530015
  • qq_31530015
  • 2016-06-28 17:29
  • 2700

Android7.1.1上下/左右分屏的策略分析

第一部分: 一、概述     Android从7.0开始支持多窗口,官方终于支持这一功能了。其实很多ODM厂商早已实现该功能,实现方式各种各样,最通用的方案是多Stack方案,比较...
  • lp542718520
  • lp542718520
  • 2017-06-08 16:27
  • 2433

Android6.0 WMS(十一) WMS窗口动画生成及播放

上一篇我们我们分析到有VSync信号过来,最后会调用WindowAnimator的animateLocked函数来生成和播放动画,这篇我们我们主要从这个函数开始分析。 animateLocked函数...
  • kc58236582
  • kc58236582
  • 2017-01-12 15:13
  • 1194

Android 7.1 GUI系统-窗口管理WMS-Surface管理(四)

Surface的管理 Surface是窗口能真正显示到物理屏幕上的基础,由surfaceflinger管理,可以通过WindowStateAnimator.java中的变量mDrawState来查看...
  • lin20044140410
  • lin20044140410
  • 2017-12-13 23:27
  • 574

Android 7.1 GUI系统-窗口管理WMS-窗口大小计算(五)

窗口大小的计算 一个应用窗口,除了应用程序本身的内容外,还有状态栏,可能还有输入法窗口,状态栏的大小是固定的,输入法窗口可以在AndroidManifest.xml中配置,相关属性如下: 以sta...
  • lin20044140410
  • lin20044140410
  • 2017-12-16 22:44
  • 67

Android 7.1 GUI系统-窗口管理WMS-窗口属性(二)

窗口类型及属性。 1),Android都有那些窗口类型,定义在WindowManager.java的内部类LayoutParams中。 public static class LayoutPa...
  • lin20044140410
  • lin20044140410
  • 2017-12-09 11:23
  • 45

图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)

原文链接: http://www.cnblogs.com/samchen2009/p/3367496.html Android 的窗口管理系统 (View, Canvas, WindowMa...
  • yypony
  • yypony
  • 2014-02-19 15:41
  • 1768

Android源码剖析之Framework层进阶版(Wms窗口管理)

本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 上一篇我们主要讲了Ams,篇幅有限,本篇再讲讲Wms,即WindowManagerService,管...
  • liuxian13183
  • liuxian13183
  • 2016-08-26 18:57
  • 1622

Android6.0 WMS(七) 窗口Z轴位置

通过前面几篇文章的学习,我们知道了在Android系统中,无论是普通的Activity窗口,还是特殊的输入法窗口和壁纸窗口,它们都是被WindowManagerService服务组织在一个窗口堆栈中的...
  • kc58236582
  • kc58236582
  • 2016-12-27 10:20
  • 1207

Android 窗口管理:如何添加窗口到WMS

本文以启动一个新的activity为例,说明如何添加新的窗口到WMS。         以下为启动一个activity时,跟WMS相关的流程图。如果对启动activity有兴趣,可以参看一些AMS的文...
  • april_12345
  • april_12345
  • 2016-10-19 14:24
  • 921
    个人资料
    • 访问:35513次
    • 积分:1686
    • 等级:
    • 排名:千里之外
    • 原创:130篇
    • 转载:38篇
    • 译文:0篇
    • 评论:9条
    最新评论