You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确实现自定义View每帧重绘?解决RenderInspector超时警告

解决自定义View每帧重绘导致的RenderInspector警告及正确实现方式

问题原因

你在onDraw()中调用invalidate()会触发无限重绘循环:invalidate()会请求View重新绘制,进而再次调用onDraw(),如此反复会让系统渲染队列持续积压,最终触发QueueBuffer time out警告。

正确实现每帧重绘的两种方式

方式一:使用Choreographer(推荐)

Choreographer能和系统的VSYNC信号同步,确保每帧只触发一次重绘,是最贴合Android渲染机制的方案:

class MainView(context: Context, attributeSet: AttributeSet?) : FrameLayout(context, attributeSet) {
    private val frameCallback = object : Choreographer.FrameCallback {
        override fun doFrame(frameTimeNanos: Long) {
            // 在此更新绘制所需的数据(比如动画进度、坐标等)
            invalidate()
            // 注册下一帧的回调,持续触发重绘
            Choreographer.getInstance().postFrameCallback(this)
        }
    }

    init {
        setWillNotDraw(false)
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        // View附着到窗口时开始帧回调
        Choreographer.getInstance().postFrameCallback(frameCallback)
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        // View脱离窗口时移除回调,避免内存泄漏
        Choreographer.getInstance().removeFrameCallback(frameCallback)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        // 编写你的自定义绘制逻辑
    }
}

方式二:使用ValueAnimator

利用无限循环的ValueAnimator监听帧更新,间接触发重绘,实现起来更简洁:

class MainView(context: Context, attributeSet: AttributeSet?) : FrameLayout(context, attributeSet) {
    private val updateAnimator = ValueAnimator.ofFloat(0f, 1f).apply {
        repeatCount = ValueAnimator.INFINITE
        repeatMode = ValueAnimator.RESTART
        // 无需精确设置时长,系统会自动对齐VSYNC
        addUpdateListener {
            invalidate()
        }
    }

    init {
        setWillNotDraw(false)
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        updateAnimator.start()
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        updateAnimator.cancel()
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        // 编写你的自定义绘制逻辑
    }
}

关键注意事项

  • 必须在onDetachedFromWindow()中停止回调/动画,防止View被销毁后仍持有引用导致内存泄漏。
  • 两种方式都基于系统VSYNC信号,不会产生无限循环,能保证渲染队列稳定,避免超时警告。

内容的提问来源于stack exchange,提问作者p851523

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 17:34:51