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

多View绘制进度矩形50ms刷新卡顿,求流畅兼性能优化方案

优化方案

1. 合并定时任务,避免重复调度

不要给30个视图各自创建定时任务,改用全局统一调度:一次定时任务触发所有视图的重绘请求。原方案中30个单线程定时任务会导致调度器任务队列堆积,全局调度能减少调度压力,同时保证所有视图同步更新。

示例修改:

// 全局维护所有需要更新的视图列表
private val progressViews = mutableListOf<YourViewType>()

init {
    // 只创建一个全局定时任务
    backgroundEach(50) {
        progressViews.forEach { it.postInvalidateOnAnimation() }
    }
    // 当前视图加入列表
    progressViews.add(view)
    register(view.eventOnDraw.listen(::onDraw))
}

2. 替换postInvalidate为postInvalidateOnAnimation

postInvalidate会立即向UI线程发送重绘消息,短时间内大量发送会导致消息队列阻塞。postInvalidateOnAnimation会将重绘请求合并到系统下一帧的绘制流程(和Choreographer同步),避免冗余的重绘操作,更贴合Android的绘制机制。

3. 改用scheduleWithFixedDelay替代scheduleAtFixedRate

你的backgroundEach使用scheduleAtFixedRate,它会严格按固定间隔触发任务,不管上一次任务是否执行完成,单线程调度器下极易出现任务堆积。换成scheduleWithFixedDelay,它会在上一次任务执行完毕后再等待指定间隔触发,避免调度队列积压。

4. 缓存计算结果,减轻onDraw负担

onDraw方法会被频繁调用,要避免在其中做重复计算:

  • 缓存player.commands.size的值,避免每次onDraw都读取
  • 提前计算进度值,不要在onDraw中访问player的属性(如果player的方法调用有耗时操作,会直接拖慢绘制)

示例修改:

// 缓存命令总数
private var commandCount = player.commands.size
// 缓存当前进度
private var currentProgress = 0f

// 定时任务中先计算进度,再触发重绘
backgroundEach(50) {
    currentProgress = player.asStarted()?.inLoopIndex?.div(commandCount.toFloat()) ?: 0f
    progressViews.forEach { it.postInvalidateOnAnimation() }
}

private fun onDraw(canvas: Canvas) {
    if (currentProgress > 0) {
        canvas.drawRect(0f, 0f, width * currentProgress, height.toFloat(), paint)
    }
}

5. 用ValueAnimator驱动进度(推荐方案)

放弃手动定时任务,改用Android系统的ValueAnimator,它的回调会和系统帧信号同步(默认60fps),能精准控制进度更新,且不会产生多余的重绘请求,同时天然支持进度的平滑过渡。

示例代码:

private val progressAnimator = ValueAnimator.ofFloat(0f, 1f).apply {
    // 根据总步数计算单次循环时长,或设置为固定值
    duration = player.commands.size * 50L
    repeatCount = ValueAnimator.INFINITE
    addUpdateListener { anim ->
        currentProgress = anim.animatedValue as Float
        view.postInvalidateOnAnimation()
    }
}

init {
    progressAnimator.start()
    register(view.eventOnDraw.listen(::onDraw))
}

private fun onDraw(canvas: Canvas) {
    if (currentProgress > 0) {
        canvas.drawRect(0f, 0f, width * currentProgress, height.toFloat(), paint)
    }
}

6. 开启硬件加速优化绘制

确保视图开启硬件加速(默认开启),绘制矩形这类简单图形时,GPU会直接处理,大幅降低UI线程的负载。若视图有复杂绘制,可设置view.layerType = View.LAYER_TYPE_HARDWARE,让视图拥有独立的硬件层,减少重绘时的计算量。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 11:02:00