Как синхронизировать частоту кадров с Android
Я ищу способ синхронизировать некоторую активность кода с частотой кадров дисплея Android. Это небольшой фрагмент кода, который просто устанавливает цвет небольшой области отображения, и ничего более. Есть какой-то метод или ловушка, которые я могу использовать для этой цели?
Я могу использовать таймер, работающий с очень быстрыми интервалами, но рендеринг, похоже, страдает от наложения частоты кадров. Например, моя частота кадров составляет 60 Гц, поэтому, если я установлю интервал таймера на 1/60 секунды, внешний вид будет неоднородным. Я не могу установить таймер точно на 16,666 мсек, и даже если бы смог, я все равно видел бы псевдонимы.
Благодарю.
1 ответ
Я знаю, что это старый вопрос, но я сам столкнулся с этой проблемой и создал симпатичный небольшой служебный класс, который делает именно это.
Котлин Класс:
/**
* Small utility class that allows for [doFrame] to be executed every frame based on the native
* [Choreographer] instead of using precomputed values and timers.
* [doFrame] is run on the main thread and is executed on the next frame.
* The [SyncedRenderer] can be restarted freely.
*/
class SyncedRenderer(val doFrame: (frameTimeNanos: Long) -> Unit) {
private var callback: (Long) -> Unit = {}
fun start() {
callback = {
doFrame(it)
Choreographer.getInstance().postFrameCallback(callback)
}
Choreographer.getInstance().postFrameCallback(callback)
}
fun stop() {
Choreographer.getInstance().removeFrameCallback(callback)
callback = {}
}
}
Применение:
val renderer = SyncedRenderer { frameTimeNanos: Long ->
// My code here will execute on main thread every frame
}
// Example when dragging something
override fun onStartDrag() {
renderer.start()
}
override fun onReleaseDrag() {
renderer.stop()
}
Я обнаружил, что это ненамного эффективнее, чем просто использование фиксированной ставки. Timer
и запускать код с частотой обновления каждого кадра.
Однако с этой реализацией вы не запускаете какой-либо код в фоновом потоке, поэтому вам не нужно вызывать какие-либо post
или связанные с ним методы при изменении View
с.
Что еще более важно, дополнительное выполнение не выполняется, чем необходимо, поэтому это может быть очень полезно для более плавной прокрутки и анимации по сравнению с использованием жестко запрограммированного таймера частоты обновления.
Надеюсь, это кому-то поможет:)
После некоторых поисков и экспериментов, одним из решений является использование класса Choreographer, который предоставляет способ привязать функцию обратного вызова к частоте кадров. Ниже приведен код. Я обнаружил, что это показывает небрежное время на медленных телефонах. Последние модели телефонов Samsung работают лучше.
private FrameCallback frameCallback = null;
private boolean frameCallbackPending = false;
public void armVSyncHandler() {
if(!frameCallbackPending) {
frameCallbackPending = true;
if(frameCallback == null)
{
frameCallback = new FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
frameCallbackPending = false;
// Do some work here
armVSyncHandler();
}
};
}
Choreographer.getInstance().postFrameCallback(frameCallback);
}
}