布景

脱离事务场景讲技能计划都是耍流氓

最近接手了IM的事务,一上来就来了几个大需求,搞得有点手忙脚乱。在做需求的过程中发现,咱们的会话列表(RecyclerView)竟然每次更新都是notifyDataSetChanged(),因为IM的改写频率是十分高的

咱们能够想象一下微信会话列表,每来1条消息,就大局调用notifyDataSetChanged。

这儿瞎猜一下,或许由于历史原因,之前设计的同学也是不得已而为之。已然发现了这个问题,那么咱们如何来进行优化呢?

IM列表跟普通列表的差异

  • 有序性:列表中的Item按时刻排序,或许其他规矩(置顶也是修正时刻完结)
  • 仅有性:每个会话都是仅有的,不存在重复
  • 单item更新频率高:能够参考微信的会话列表

DiffUtil

首要想到的是DiffUtil,它用来比较两个数据集,寻找出旧数据集->新数据集的最小改变量
完结思路:

  • 获取原始会话数据,进行排序,去重操作
  • 选用DiffUtil主动计算新老数据集差异,主动完结定向改写

这儿只摘取DiffUtil关键使用部分,至于高档用法和更高档的用法不再赘述

class DiffMsgCallBack: DiffUtil.Callback() {
    private val oldData: MutableList<MsgItem> = mutableListOf()
    private val newData: MutableList<MsgItem> = mutableListOf()
    //老数据集size
    override fun getOldListSize(): Int {
        return oldData.size
    }
    //新数据集size
    override fun getNewListSize(): Int {
        return newData.size
    }
    /**
     * 比较的是position,被DiffUtil调用,用来判断两个目标是否是相同的Item
     * 例如,如果你的Item有仅有的id字段,这个办法就 判断id是否持平
     */
    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldData[oldItemPosition].id == newData[newItemPosition].id
    }
    /**
     * 用来查看 两个item是否含有相同的数据,当前item的内容是否发生了改变,这个办法仅仅在areItemsTheSame()返回true时,才调用
     */
    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        if (oldData[oldItemPosition].id != newData[newItemPosition].id){
            return false
        }
        if (oldData[oldItemPosition].content != newData[newItemPosition].content){
            return false
        }
        if (oldData[oldItemPosition].time != newData[newItemPosition].time){
            return false
        }
        return true
    }
    /**
     * 高档用法:完结部分(partial)绑定的办法,需求配合onBindViewHolder的3个参数的办法
     * 更高档用法:AsyncListDiffer+ListAdapter
     * 
     */
    override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? {
        return super.getChangePayload(oldItemPosition, newItemPosition)
    }

SortedList

当我认为DiffUtil已经能够满意需求的时分,无意间又发现了一个SortedList

SortedList是一个有序列表(数据集)的完结,能够保持ItemData都是有序的,并(主动)告诉列表(RecyclerView)(数据集)中的更改。

调配RecyclerView使用,去重,有序,主动定向改写

这儿也只摘取关键使用部分,具体用法不再详解

class SortListCallBack(adapter: RecyclerView.Adapter<*>?) : SortedListAdapterCallback<MsgItem>(adapter) {
    /**
     * 排序条件,完结排序的逻辑
     */
    override fun compare(o1: MsgItem?, o2: MsgItem?): Int {
        o1 ?: return -1
        o2 ?: return -1
        return o1.time - o2.time
    }
    /**
     * 和DiffUtil办法共同,用来判断 两个目标是否是相同的Item。
     */
    override fun areItemsTheSame(item1: MsgItem?, item2: MsgItem?): Boolean {
        return item1?.id == item2?.id
    }
    /**
     * 和DiffUtil办法共同,返回false,代表Item内容改变。会回调mCallback.onChanged()办法;
     * 相同:areContentsTheSame+areItemsTheSame
     */
    override fun areContentsTheSame(oldItem: MsgItem?, newItem: MsgItem?): Boolean {
        if (oldItem?.id != newItem?.id){
            return false
        }
        if (oldItem?.content != newItem?.content){
            return false
        }
        if (oldItem?.time != newItem?.time){
            return false
        }
        return true
    }
    /**
     * 高档用法:完结部分绑定的办法,需求配合onBindViewHolder的3个参数的办法
     */
    override fun getChangePayload(item1: MsgItem?, item2: MsgItem?): Any? {
        return super.getChangePayload(item1, item2)
    }
}

对比

DiffUtil和SortedList是十分类似的,修正过数据后,内部持有的回调接口都是同一个:androidx.recyclerview.widget.ListUpdateCallback

/**
 * An interface that can receive Update operations that are applied to a list.
 * <p>
 * This class can be used together with DiffUtil to detect changes between two lists.
 */
public interface ListUpdateCallback {
    void onInserted(int position, int count);
    void onRemoved(int position, int count);
    void onMoved(int fromPosition, int toPosition);
    void onChanged(int position, int count, @Nullable Object payload);

DiffUtil计算出Diff或许SortedList察觉出数据集有改变后,会回调ListUpdateCallback接口的这四个办法,DiffUtil和SortedList供给的默认Callback完结中,都会告诉Adapter完结定向改写。
这便是主动定向改写的原理

总结

  • DiffUtil比较两个数据源(一般是List)的差异(Diff),Callback中比对时传递的参数是 position
  • SortedList能完结数据集的排序和去重,Callback中比对时,传递的参数是ItemData
  • 都能完结主动定向改写 + 部分绑定,一种主动定向改写的手法
  • DiffUtil: 检测不出重复的,会被认为是新增的
  • DiffUtil高档用法支撑子线程中处理数据,而SortList不支撑

抱负与现实

2种计划都有了,是不是能够进行IM会话列表的优化了呢,答案是不能

  • 事务需求迭代,牵一发而动全身
  • 祖传代码,无人敢动,更甭说优化了

有时分咱们写代码会想着后面再优化一下,但是许多时分都不会给你优化的机会,除非严重需求变动,所以一开始设计结构的时分就要结合事务场景尽量设计的愈加合理

参考文章:blog.csdn.net/zxt0601/art…

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。