【面试专题】Android屏幕刷新机制,带你轻松理解Android-Hook机制

Choreographer

初始化

mChoreographer,是在ViewRootImpl的构造方法内使用 Choreographer.getInstance()创建。

Choreographer和Looper一样是线程单例的,通过ThreadLocal机制来保证唯一性。因为Choreographer内部通过FrameHandler来发送消息,所以初始化的时候会先判断当前线程有无Looper,没有的话直接抛异常。

public static Choreographer getInstance() {

return sThreadInstance.get();

}

private static final ThreadLocal sThreadInstance =

new ThreadLocal() {

@Override

protected Choreographer initialValue() {

Looper looper = Looper.myLooper();

if (looper == null) {

//当前线程要有looper,Choreographer实例需要传入

throw new IllegalStateException(“The current thread must have a looper!”);

}

Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);

if (looper == Looper.getMainLooper()) {

mMainInstance = choreographer;

}

return choreographer;

}

};

postCallback

mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null)方法,第一个参数是CALLBACK_TRAVERSAL,表示回调任务的类型,共有以下5种类型:

//输入事件,首先执行

public static final int CALLBACK_INPUT = 0;

//动画,第二执行

public static final int CALLBACK_ANIMATION = 1;

//插入更新的动画,第三执行

public static final int CALLBACK_INSETS_ANIMATION = 2;

//绘制,第四执行

public static final int CALLBACK_TRAVERSAL = 3;

//提交,最后执行,

public static final int CALLBACK_COMMIT = 4;

复制代码

五种类型任务对应存入对应的CallbackQueue中,每当收到 VSYNC 信号时,Choreographer 将首先处理 INPUT 类型的任 务,然后是 ANIMATION 类型,最后才是 TRAVERSAL 类型。

postCallback()内部调用postCallbackDelayed(),接着又调用postCallbackDelayedInternal(),正常消息执行scheduleFrameLocked,延迟运行的消息会发送一个MSG_DO_SCHEDULE_CALLBACK类型的meessage:

private void postCallbackDelayedInternal(int callbackType,

Object action, Object token, long delayMillis) {

synchronized (mLock) {

mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

if (dueTime <= now) { //立即执行

scheduleFrameLocked(now);

} else {

//延迟运行,最终也会走到scheduleFrameLocked()

Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);

msg.arg1 = callbackType;

msg.setAsynchronous(true);

mHandler.sendMessageAtTime(msg, dueTime);

}

}

}

FrameHandler这个类是内部专门用来处理消息的,可以看到延迟的MSG_DO_SCHEDULE_CALLBACK类型消息最终也是走到scheduleFrameLocked:

private final class FrameHandler extends Handler {

public FrameHandler(Looper looper) {

super(looper);

}

@Override

public void handleMessage(Message msg) {

switch (msg.what) {

case MSG_DO_FRAME:

// 执行doFrame,即绘制过程

doFrame(System.nanoTime(), 0);

break;

case MSG_DO_SCHEDULE_VSYNC:

//申请VSYNC信号,例如当前需要绘制任务时

doScheduleVsync();

break;

case MSG_DO_SCHEDULE_CALLBACK:

//需要延迟的任务,最终还是执行上述两个事件

doScheduleCallback(msg.arg1);

break;

}

}

}

void doScheduleCallback(int callbackType) {

synchronized (mLock) {

if (!mFrameScheduled) {

final long now = SystemClock.uptimeMillis();

if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {

scheduleFrameLocked(now);

}

}

}

}

申请VSync信号

scheduleFrameLocked()方法里面就会去真正的申请 VSync 信号了。

private void scheduleFrameLocked(long now) {

if (!mFrameScheduled) {

mFrameScheduled = true;

if (USE_VSYNC) {

//当前执行的线程,是否是mLooper所在线程

if (isRunningOnLooperThreadLocked()) {

//申请 VSYNC 信号

scheduleVsyncLocked();

} else {

// 若不在,就用mHandler发送消息到原线程,最后还是调用scheduleVsyncLocked方法

Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);

msg.setAsynchronous(true);//异步

mHandler.sendMessageAtFrontOfQueue(msg);

}

} else {

// 如果未开启VSYNC则直接doFrame方法(4.1后默认开启)

final long nextFrameTime = Math.max(

mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);

Message msg = mHandler.obtainMessage(MSG_DO_FRAME);

msg.setAsynchronous(true);//异步

mHandler.sendMessageAtTime(msg, nextFrameTime);

}

}

}

VSync信号的注册和监听是通过mDisplayEventReceiver实现的。mDisplayEventReceiver是在Choreographer的构造方法中创建的,是FrameDisplayEventReceiver的实例。 FrameDisplayEventReceiver是 DisplayEventReceiver 的子类,

private void scheduleVsyncLocked() {

mDisplayEventReceiver.scheduleVsync();

}

public DisplayEventReceiver(Looper looper, int vsyncSource) {

if (looper == null) {

throw new IllegalArgumentException(“looper must not be null”);

}

mMessageQueue = looper.getQueue();

// 注册native的VSYNC信号监听者

mReceiverPtr = nativeInit(new WeakReference(this), mMessageQueue,vsyncSource);

mCloseGuard.open(“dispose”);

}

VSync信号回调

native的VSync信号到来时,会走到onVsync()回调:

private final class FrameDisplayEventReceiver extends DisplayEventReceiver

implements Runnable {

@Override

public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {

//将本身作为runnable传入msg, 发消息后 会走run(),即doFrame(),也是异步消息

Message msg = Message.obtain(mHandler, this);

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
[外链图片转存中…(img-b9rjEnyM-1710931322483)]
[外链图片转存中…(img-WC05KrFU-1710931322484)]
[外链图片转存中…(img-tq6rimx1-1710931322484)]
[外链图片转存中…(img-Pp4CD8AY-1710931322484)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-SHLBeIWr-1710931322485)]

  • 29
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值