Как определить начало / остановку обновления экрана устройства на мобильных устройствах

#android #ios

#Android #iOS

Вопрос:

На устройстве с частотой 60 Гц экран обновляется один раз каждые ~ 16,67 мс (я видел, что это называется частотой обновления и количеством переворотов). Для определенных исследований это на самом деле приличный промежуток времени. Есть ли какой-либо способ получить точную временную метку или событие, когда экран обновляется или начинает обновляться?

Комментарии:

1. На iOS вы можете использовать CADisplayLink : developer.apple.com/documentation/quartzcore/cadisplaylink

2. Это точный ответ, который я искал. Из любопытства, почему вы добавили это в качестве комментария вместо ответа?

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();