窗口动画管理
Android的应用启动时,或者切换Activity时都会以动画方式显示前后两屏切换的过程。动画的原理:把一帧帧的图像按一定时间间隔显示出来就完成了。
动画绘制需要定时驱动,通常的做法是启动一个定时消息,每个一定时间发一个消息,收到消息后输出一帧画面。Android支持VSync信号后,动画的驱动就由VSync信号来承担。窗口动画的基本元素是窗口Surface中保存的图像,通过对窗口的Surface设置不同的变换矩阵和透明度,然后强制Surface刷新,就能在屏幕上显示出窗口的变换过程。
1.1 接收VSync信号
WindowManagerService中有一个Choregrapher类型变量mChoreographer,如下所示:
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
...
final Choreographer mChoreographer = Choreographer.getInstance();
....
}
分析:Choreographer对象是通过Choregrapher类的静态方法getInstance()创建的,代码如下:
Choreographer.java
public static Choreographer getInstance() {
return sThreadInstance.get();
}
分析:在getInstance()方法中调用了静态变量sThreadInstance的get()方法来获得Choreographer对象。sThreadInstance的定义如下:
// Thread local storage for the choreographer.
private static final ThreadLocal<Choreographer> sThreadInstance =
new ThreadLocal<Choreographer>() {
@Override
protected Choreographer initialValue() {
Looper looper = Looper.myLooper();
if (looper == null) {
throw new IllegalStateException("The current thread must have a looper!");
}
return new Choreographer(looper);
}
};
分析:sThreadInstance 是一个线程局部存储变量,在它的initialValue()方法中创建了Choreographer对象并返回。这里使用线程局部存储的目的是为了在线程中只有一个Choreographer对象,因为Choreographer对象需要和线程的Looper对象关联在一起。
看看Choreographer的构造方法:
private Choreographer(Looper looper) {
mLooper = looper;
//创建处理消息的Handler对象
mHandler = new FrameHandler(looper);
//创建接收VSync信号的FrameDisplayEventReceiver对象
mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
mLastFrameTimeNanos = Long.MIN_VALUE;
//计算刷新的时间间隔
mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
//创建了3个CallbackQueue对象
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
}
在Choregrapher的构造方法中,最重要的是创建了FrameDisplayEventReceiver对象,这个对象能够接收VSync信号。FrameDisplayEventReceiver类继承自DisplayEventReceiver类,来看看DisplayEventReceiver类的构造方法,如下:
DisplayEventReceiver.java
public DisplayEventReceiver(Looper looper) {
if (looper == null) {
throw new IllegalArgumentException("looper must not be null");
}
mMessageQueue = looper.getQueue();
//native层进行初始化
mReceiverPtr = nativeInit(this, mMessageQueue);
mCloseGuard.open("dispose");
}
DisplayEventReceiver的构造方法中又调用了nativeInit()方法,它在native层对应的函数如下:
android-5.0.0_r6\source\frameworks\base\core\jni
android_view_DisplayEventReceiver.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj,
jobject messageQueueObj) {
...
sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
receiverObj, messageQueue);
status_t status = receiver->initialize();
if (status) {
String8 message;
message.appendFormat("Failed to initialize display event receiver. status=%d", status);
jniThrowRuntimeException(env, message.string());
return 0;
}
receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
return reinterpret_cast<jlong>(receiver.get());
}
分析:nativeInit()函数中创建了NativeDisplayEventReceiver对象,并调用它的initialize()函数.在NativeDisplayEventReceiver类中定义一个DisplayEventReceiver类的变量,如下:
class NativeDisplayEventReceiver : public LooperCallback {
public:
NativeDisplayEventReceiver(JNIEnv* env,
jobject receiverObj, const sp<MessageQueue>& messageQueue);
status_t initialize();
void dispose();
status_t scheduleVsync();
private:
jobject mReceiverObjGlobal;
sp<MessageQueue> mMessageQueue;
DisplayEventReceiver mReceiver;
bool mWaitingForVsync;
virtual int handleEvent(int receiveFd, int events, void* data);
bool processPendingEvents(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount);
void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
};
看看initialize():
status_t NativeDisplayEventReceiver::initialize() {
status_t result = mReceiver.initCheck();
//错误处理
int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
this, NULL);
//错误处理
return OK;
}
分析:在这个方法中,调用了mReceiver对象的getFd()函数得到句柄设置到了Looper对象中,这样一旦句柄有了数据到来,就能通过Looper对象来处理。