Android Studio onBindViewHolder过程耗时导致2300ms卡顿的解决方法

22 阅读2分钟
20:26:44.466 D onBindViewHolder end duration:5 ms 
20:26:44.466 D onCreateViewHolder start 
20:26:44.476 D inflateAndInit=9 ms 
20:26:44.476 D onCreateViewHolder end 
20:26:44.476 D onBindViewHolder start 
20:26:44.478 D bind
...
20:26:46.194 D onBindViewHolder end duration:2 ms 
20:26:46.194 D onCreateViewHolder start 
20:26:46.202 D inflateAndInit=7 ms 
20:26:46.202 D onCreateViewHolder end 
20:26:46.202 D onBindViewHolder start 
20:26:46.204 D bind
20:26:46.388 I Davey! duration=2310ms; Flags=1, IntendedVsync=468755453549798, Vsync=468755694290532, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=468755696759855, AnimationStart=468755696769480, PerformTraversalsStart=468755698176189, DrawStart=468757624058091, SyncQueued=468757755773604, SyncStart=468757756304437, IssueDrawCommandsStart=468757759398438, SwapBuffers=468757762351855, FrameCompleted=468757764867772, DequeueBufferDuration=473084, QueueBufferDuration=946750, GpuCompleted=0,

原理加载时逐步渲染ViewHolders,RecycleView本身是一次性创建全部onBindViewHolder,那我们就分多次提交信息!

实际上我完全没有优化加载,只是及时的去渲染,这样我们就不会跳帧2310ms了!

viewModel.timeCells.observe(viewLifecycleOwner) { cells ->
    submitGradually(meetingTimeGridAdapter, cells, firstBatch = 2, chunk = 2)
}
@Suppress("SameParameterValue")
private fun <T> submitGradually(
    adapter: ListAdapter<T, *>,
    all: List<T>,
    firstBatch: Int,
    chunk: Int
) {
    val size = all.size
    var upto = minOf(firstBatch, size)
    adapter.submitList(all.subList(0, upto).toList()) {
        val choreographer = Choreographer.getInstance()
        val cb = object : Choreographer.FrameCallback {
            override fun doFrame(frameTimeNanos: Long) {
                if (upto >= size) return
                val next = minOf(upto + chunk, size)
                // 必须传新列表对象
                adapter.submitList(all.subList(0, next).toList()) {
                    upto = next
                    if (upto < size) choreographer.postFrameCallback(this)
                }
            }
        }
        choreographer.postFrameCallback(cb)
    }
}