#android #ios
#Android #iOS
Вопрос:
На устройстве с частотой 60 Гц экран обновляется один раз каждые ~ 16,67 мс (я видел, что это называется частотой обновления и количеством переворотов). Для определенных исследований это на самом деле приличный промежуток времени. Есть ли какой-либо способ получить точную временную метку или событие, когда экран обновляется или начинает обновляться?
Комментарии:
1. На iOS вы можете использовать
CADisplayLink
: developer.apple.com/documentation/quartzcore/cadisplaylink2. Это точный ответ, который я искал. Из любопытства, почему вы добавили это в качестве комментария вместо ответа?
3. Я добавил ответ для iOS и Android.
Ответ №1:
На iOS вы можете использовать CADisplayLink
: https://developer.apple.com/documentation/quartzcore/cadisplaylink
Объект таймера, который позволяет вашему приложению синхронизировать его отображение с частотой обновления дисплея.
Пример:
import Foundation
import UIKit
public class DisplayFrameSync {
private var displayLink: CADisplayLink? = nil
private var frameUpdate: (() -> Void)? = nil
deinit {
self.stop()
}
@objc
private func onTick(displayLink: CADisplayLink) {
if let onFrameUpdate = self.frameUpdate {
onFrameUpdate()
}
}
public func start(_ update: () -> Void) {
self.displayLink?.remove(from: .main, forMode: .default)
self.displayLink?.remove(from: .main, forMode: .tracking)
self.displayLink?.invalidate()
self.displayLink = nil
self.frameUpdate = update
self.displayLink = CADisplayLink(target: self, selector: #selector(onTick(displayLink:)))
self.displayLink?.preferredFramesPerSecond = 60
self.displayLink?.add(to: .main, forMode: .default)
self.displayLink?.add(to: .main, forMode: .tracking)
}
public func stop() {
self.displayLink?.remove(from: .main, forMode: .default)
self.displayLink?.remove(from: .main, forMode: .tracking)
self.displayLink?.invalidate()
self.displayLink = nil
self.frameUpdate = nil
}
}
Использование:
let ds = DisplayFrameSync()
ds.start({
print("Frame Update")
});
DispatchQueue.main.asyncAfter(.now() 2.0) {
ds.stop()
}
Используя вышесказанное, вы также можете сделать свой собственный animateWithDuration
и отслеживать время самостоятельно, Date.timeIntervalSinceReferenceDate
вычитая каждый кадр из текущего времени..
Для Android вы можете использовать Choreographer
:
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.Choreographer;
private class DisplayFrameSync extends Thread implements Choreographer.FrameCallback {
private volatile Handler signal;
private Consumer<Long> update;
public DisplayFrameSync(Consumer<Long> update) {
super();
this.update = update;
}
@Override
public void run() {
setName("DisplayFrameSyncThread");
Looper.prepare();
signal = new Handler() {
public void handleMessage(Message msg) {
Looper.myLooper().quit();
}
};
Choreographer.getInstance().postFrameCallback(this);
Looper.loop();
Choreographer.getInstance().removeFrameCallback(this);
}
public void signal() {
if (this.signal != null) {
this.signal.sendEmptyMessage(0);
this.signal = null;
}
}
@Override
public void doFrame(long timeNano) {
if (this.update != null) {
this.update.accept(timeNano);
}
Choreographer.getInstance().postFrameCallback(this);
}
}
Здесь уже указано время для каждого рендеринга кадра для вас..
Использование:
DisplayFrameSync ds = new DisplayFrameSync((timeNano) -> {
System.out.println("Frame Update");
});
ds.start();
//Later..
ds.stop();