RecyclerView优化:DiffUtil的使用

2019-06-15  本文已影响0人  魏树鑫

RecyclerView相比ListView已经有局部的定向更新,但是如果涉及到大量的数据的更新,比如执行刷新操作后,正常需要替换所有的数据,然后调用adapter.notifyDataSetChanged()进行全量更新;但是可能出现界面闪烁;另外大多数时候有一部分数据其实没有变化,理论上并不需要重新绑定;

DiffUtil使用场景

性能对比

The test list is composed of random UUID Strings and the tests are run on Nexus 5X with M

DiffUtil使用的算法

算法看不懂,可参考这个 https://www.jianshu.com/p/7f1473c2e521

用例

class RecyclerViewActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_recyclerview)

        supportActionBar!!.title = "RecyclerView"
        add.setOnClickListener {
            val data = ArrayList<User>()
            for (i in 42..100) {
                data.add(User("name $i", i))
            }
            val calculateDiff = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
                override fun getOldListSize(): Int {
                    return recyclerView.adapter?.itemCount ?: 0
                }

                override fun getNewListSize(): Int {
                    return data.size
                }

                override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
                    return data[newItemPosition] == (recyclerView.adapter as RecyclerViewAdapter).data[oldItemPosition]
                }

                override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
                    return data[newItemPosition].name === (recyclerView.adapter as RecyclerViewAdapter).data[oldItemPosition].name
                }

            })
            (recyclerView.adapter as RecyclerViewAdapter).data = data
            calculateDiff.dispatchUpdatesTo(recyclerView.adapter!!)
        }

        recyclerView.initRecyclerView()
    }
}

class RecyclerViewAdapter : RecyclerView.Adapter<ViewHolder>() {
    var data: List<User> = ArrayList()
        set(value) {
            field = value
            notifyDataSetChanged()
        }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val contentView = LayoutInflater.from(parent.context).inflate(R.layout.adapter_item_recyclerview, parent, false)
        return object : ViewHolder(contentView) {}
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.itemView.tv_text.text = data[position].toString()
        holder.itemView.setOnClickListener { v -> Toast.makeText(v.context, "点击:$position", Toast.LENGTH_SHORT).show() }
    }

    override fun getItemCount(): Int {
        return data.size
    }
}

internal fun RecyclerView.initRecyclerView() {
    this.layoutManager = GridLayoutManager(this.context, 2, RecyclerView.VERTICAL, false)
    val verticalItemDecoration = DividerItemDecoration(this.context, DividerItemDecoration.VERTICAL)
    val horizontalItemDecoration = DividerItemDecoration(this.context, DividerItemDecoration.HORIZONTAL)
    verticalItemDecoration.setDrawable(this.context.resources.getDrawable(android.R.drawable.divider_horizontal_textfield))
    horizontalItemDecoration.setDrawable(this.context.resources.getDrawable(android.R.drawable.divider_horizontal_textfield))
    this.addItemDecoration(verticalItemDecoration)
    this.addItemDecoration(horizontalItemDecoration)
    val adapter = RecyclerViewAdapter()
    val data = ArrayList<User>()
    for (i in 0..59) {
        data.add(User("name $i", i))
    }
    adapter.data = data
    this.adapter = adapter
    adapter.notifyDataSetChanged()
}

data class User(var name: String, var age: Int) {
    override fun toString(): String {
        return "$name : $age"
    }
}
上一篇 下一篇

猜你喜欢

热点阅读