liangjingkanji / BRV

[使用文档] Android 快速构建 RecyclerView, 比 BRVAH 更简单强大
http://liangjingkanji.github.io/BRV/
MIT License
2.59k stars 327 forks source link

HoverGridLayoutManager 数据量大的时候,bindingAdapter.checkedAll()特别慢,需性能优化 #448

Closed kllkko closed 2 months ago

kllkko commented 3 months ago

问题描述

使用HoverGridLayoutManager,3000条数据,执行全选和取消全选,都要耗时10多秒

期望结果

执行全选和取消全选,在1秒内执行完

如何复现

希望快速解决请Fork仓库复现问题并附上链接, 否则只能等有空才能排查 凭空猜测只会让问题晦涩难懂, 浪费本项目可持续维护时间

在sample HoverGridFragment里面


 binding.rv.setup {
            addType<CheckModel>(R.layout.item_check_mode)
            addType<HoverHeaderModel>(R.layout.item_hover_header)

            setCheckableType(R.layout.item_check_mode)

            // 点击事件
            onClick(R.id.item) {
                when (itemViewType) {
                    R.layout.item_hover_header -> toast("悬停条目")
                    else -> toast("普通条目")
                }
            }

            onChecked { position, checked, allChecked ->
                val model = getModel<CheckModel>(position)
                model.checked = checked
                model.notifyChange()
            }
           ...
 }

private fun getData(): List<Any> {
        val list = mutableListOf<Any>()
        for (i in 0..3000){
            list.add(CheckModel())
        }

        list.add(0,HoverHeaderModel())
        list.add(100,HoverHeaderModel())
        list.add(500,HoverHeaderModel())
        list.add(1000,HoverHeaderModel())
        list.add(2000,HoverHeaderModel())

        return list
    }

添加两个按钮,执行全选和取消全选
binding.tvAll.setOnClickListener {
            lifecycleScope.launch(Dispatchers.IO){
                println("xxx 1")
                binding.rv.bindingAdapter.checkedAll(true)
                println("xxx 2")
            }
        }

        binding.tvUnselectAll.setOnClickListener {
            lifecycleScope.launch(Dispatchers.IO){
                println("xxx 1")
                binding.rv.bindingAdapter.checkedAll(false)
                println("xxx 2")
            }
        }

截图

异常堆栈信息或者手机截图/视频(拖拽到输入框即可上传) 2024-06-19 17:27:46.616 5604-5759 System.out com.drake.brv.sample I xxx 1 2024-06-19 17:27:58.935 5604-5759 System.out com.drake.brv.sample I xxx 2 耗时12秒

版本

liangjingkanji commented 3 months ago

你换成GridLayoutManager试下卡不卡

kllkko commented 3 months ago

你换成GridLayoutManager试下卡不卡

东哥好!

换成GridLayoutManager,不卡,3000条数据,checkedAll耗时0.4秒

binding.rv.grid(4).setup {
            addType<CheckModel>(R.layout.item_check_mode)

            onChecked { position, checked, allChecked ->
                val model = getModel<CheckModel>(position)
                model.checked = checked
                model.notifyChange()
            }

        }.models = getData()
    }

    private fun getData(): MutableList<Any> {
        // 在Model中也可以绑定数据
        val list = mutableListOf<Any>()
        for (i in 0..3000){
            list.add(CheckModel())
        }

        return list
    }

2024-06-19 17:54:45.571 13124-13203 System.out com.drake.brv.sample I xxx 1 2024-06-19 17:54:45.989 13124-13203 System.out com.drake.brv.sample I xxx 2

liangjingkanji commented 3 months ago

使用HoverGridLayoutManager但是不使用悬停item也会卡吗?

kllkko commented 3 months ago

使用HoverGridLayoutManager但是不使用悬停item也会卡吗?

是的,一样会卡

liangjingkanji commented 3 months ago

暂时没什么办法, HoverGridLayoutManager不是我写的, 里面比较复杂我也不熟悉, 并且目前比较忙也没什么优化思路

kllkko commented 3 months ago

暂时没什么办法, HoverGridLayoutManager不是我写的, 里面比较复杂我也不熟悉, 并且目前比较忙也没什么优化思路

我换了个写法,不使用bindingAdapter.checkedAll方法, 自己改变数据源的checked属性,响应就会很快,1秒内执行完

withContext(Dispatchers.IO){
    albumData.value!!.files.map {
        it.checked = true
        it.notifyChange()
    }
}
liangjingkanji commented 2 months ago

checkAll会遍历List, 理论上和layoutManager没任何关系

我建议你将notifyChange()放到结尾执行一次即可, 减少DataBinding渲染View的次数和时间

理论上不需要异步也可以解决

kllkko commented 1 month ago

checkAll会遍历List, 理论上和layoutManager没任何关系

我建议你将notifyChange()放到结尾执行一次即可, 减少DataBinding渲染View的次数和时间

理论上不需要异步也可以解决

是的,理论上和layoutManager没有关系,checkAll会遍历List,每改变一下list里面的数据check属性,都会触发onChecked 刷新,如果布局复杂一点而且数据量大的话,就会比较卡,这也是HoverGridLayoutManager比linear那些列表checkAll时间久些的原因,所以我的建议是看能不能调整checkAll的写法,checkAll的时候不去触发onChecked,最终的时候刷新一下