【问题标题】:How to sync to Android frame rate如何同步到 Android 帧率
【发布时间】:2017-05-18 00:13:50
【问题描述】:

我正在寻找一种将某些代码活动与 Android 显示帧速率同步的方法。这是一小段代码,它可以简单地设置一个小显示区域的颜色,仅此而已。我可以为此目的利用某种方法或钩子吗?

我可以成功使用以非常快的间隔运行的计时器,但渲染似乎受到帧速率锯齿的影响。例如,我的帧速率是 60 Hz,所以如果我将计时器间隔设置为 1/60 秒,则外观不均匀。我无法将计时器精确设置为 16.666 毫秒,即使可以,我仍然会看到混叠。

谢谢。

【问题讨论】:

    标签: java android frame synchronize


    【解决方案1】:

    我知道这是一个老问题,但我自己遇到了这个问题,并创建了一个很好的小实用程序类来完成这个。

    Kotlin 类:

    
    /**
     * 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 并以每帧刷新率运行代码略高。

    但是,通过此实现,您无需在后台线程上运行任何代码,因此您无需在修改 Views 时调用任何类型的 post 或其相关方法。

    更重要的是,虽然没有额外执行不必要的操作,因此与使用硬编码的刷新率计时器相比,这对于更平滑的滚动和动画非常有用。

    希望这可以帮助某人:)

    【讨论】:

    • 谢谢你,你拯救了我的一天)))我使用几乎所有东西,处理程序,executorSerivce,计时器,每 16.6 毫秒创建一个计划任务,但它是滞后的。此解决方案完美运行。
    【解决方案2】:

    经过一番搜索和试验,一个解决方案是使用 Choreographer 类,它提供了一种将回调函数挂钩到帧速率的方法。下面是代码。我发现它在慢速手机上显示出马虎的时间。最近型号的三星手机性能更好。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-09
      • 1970-01-01
      • 1970-01-01
      • 2013-02-11
      相关资源
      最近更新 更多