Android实用的排序集合 - SortedList

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/IO_Field/article/details/79821191

概述

SortedList继承于java.lang.Object,是android.support.v7.util包下的工具类。这个类,与java.util包下的ArrayList、List等类没有丝毫的关系,不管是继承还是实现。而,又与它们相像,在这个类的内部,封装了对一系列对数据的操作:插入,删除,移动,更新等。

SortedList实际上是一个排序列表的实现,提供处理了两种角色:

  • 保持列表的顺序
  • 分发列表更改的信息,以便绑定的RecyclerView.Adapter更新UI

也就是说,SortedList里面的数据集是按照指定的条件排序的,不需要再为排序而烦恼。而,和ArrayList、List等类的排序方式是一样的,它通过compare(Object,Object)方法对Item进行排序,这样又显得不陌生。对于Item的搜索,它采用的二进制搜索来检索Item,提高了检索的效率。

核心方法

添加

  • add(T item):添加指定的item到SortedList中
  • addAll(T… items):一次性添加多个items到SortedList中
  • addAll(Collection items):将给定的集合添加到SortedList中
  • addAll(T[] items,boolean mayModifyInput):添加给出的items到指定的list中,当mayModifyInput为true时,SortList在操作数据期间可能直接使用该数组的引用,以节省内存分配。此时,你不能够继续引用数组甚至是更改数组

删除

  • clear():清空数据集
  • remove(T item):删除指定的Item,然后调用onRemoved()方法
  • removeItemAt(int index):删除指定索引的item,然后调用onRemoved()方法

更新

  • updateItemsAt(int index,T item):更新指定索引的item,然后调用onChanged(int,int)方法,onMoved(int,int)方法

获取指定索引的Item

  • get(int index)

获取Item的索引

  • indexOf(T item)

事务

  • beginBatchedUpdates():批量处理适配器更新操作发生在调用当前方法和调用endBatchedUpdates()之间
  • endBatchedUpdates():结束更新事务,回调处理事件,和beginBatchedUpdates()一起使用

核心类

  • SortedList.Callback:在该类中,定义了一系列的SortedList操作,包括如何排序以及处理重复的Item。同时,SortedList中数据发生更改时回调相应的方法。
  • SortedList.BatchedCallback:它是SortedList.Callback的实现类,可以批量处理并SortedList分发的操作。比如,如果要将多个Item添加到SortedList,同时将Item添加到连续索引中,BatchedCallback将单个onInserted(index,1)调用转换为一个onInserted(index,N),这样可以使RecyclerView更轻松、高效的更新UI。
  • SortedListAdapterCallback:它是SortedListAdapterCallback的实现类,主要与RecyclerView.Apdater配合使用,在它内部定义了RecyclerView.Apdater,同时实现了数据集变化时的更新操作。此时,只需要实现以下3个方法即可:

    • areItemsTheSame():用于判断两个Item是否相同
    • areContentsTheSame():用于判断两个Item是否有相同的内容
    • compare():排序条件

这里需要注意的是,BatchedCallback和SortedListAdapterCallback是不同的,尽管它们都是SortedList.Callback的实现类:

  1. 在创建SortedList.BatchedCallback实例时,必须传递SortedList.Callback示例,是为了将SortedList分发的操作分发给它。这个类的主要作用是用来批量处理SortedList分发的操作。但是,不管是对Item排序,还是处理相同的Item,甚至是执行SortedList分发的操作都是由传递过来的SortedList.Callback实现。
  2. SortedListAdapterCallback只是SortedListAdapterCallback的简单实现,当SortedList与RecyclerView.Apdater配合使用时,只是实现了Adapter更新UI的部分。

简单实现

SortedList基于维持列表中Item的顺序这一特性,在实际开发过程中,还是带来很多的遍历。比如,在查看成绩列表时,只需将成绩添加至列表即可,它会自动排序,我们不需要再考虑。下面就是SortedList的示例。

  1. 创建bean类

    data class StudentBean(val no: Int, val name: String, val rank: Int)
    
  2. 创建SortedListAdapterCallback的实现类

    class StudentCallback<R : RecyclerView.ViewHolder, T : RecyclerView.Adapter<R>>(@NonNull private val adapter: T) : SortedListAdapterCallback<StudentBean>(adapter) {
    
        // 默认按照学号排序
        private var sortedType = SortedListActivity.SortedType.RANK
    
        // 判断两个Item是否相同
        override fun areItemsTheSame(item1: StudentBean?, item2: StudentBean?): Boolean {
            return item1?.no == item2?.no
        }
    
        // 排序条件
        override fun compare(o1: StudentBean?, o2: StudentBean?): Int {
            return when (sortedType) {
                SortedListActivity.SortedType.NO -> o1!!.no - o2!!.no
                SortedListActivity.SortedType.NO_REVERSE -> o2!!.no - o1!!.no
                SortedListActivity.SortedType.RANK -> o1!!.rank - o2!!.rank
                SortedListActivity.SortedType.RANK_REVERSE -> o2!!.rank - o1!!.rank
            }
        }
    
        // 判断两个Item的内容是否相同
        override fun areContentsTheSame(oldItem: StudentBean?, newItem: StudentBean?): Boolean {
            return oldItem == newItem
        }
    
        // 设置排序类型
        fun setType(type: SortedListActivity.SortedType) {
            this.sortedType = type
        }
    
    }
    

    在StudentCallback这个实现类中,指定了按学号正序/逆序或者排名正序/逆序这这四种方式进行排序。

  3. 创建Adapter

    扫描二维码关注公众号,回复: 2942411 查看本文章

    class StudentAdapter : RecyclerView.Adapter() {

    val mCallback = StudentCallback(this)
    
    val mSortedList = SortedList<StudentBean>(StudentBean::class.java, SortedList.BatchedCallback<StudentBean>(mCallback))
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StudentViewHolder {
        val view = LayoutInflater.from(parent.context)
                .inflate(R.layout.item_student, parent, false)
        return StudentViewHolder(view)
    }
    
    override fun getItemCount(): Int {
        return mSortedList.size()
    }
    
    override fun onBindViewHolder(holder: StudentViewHolder, position: Int) {
        val bean = mSortedList.get(position)
    
        holder.tvNoValue.text = bean.no.toString()
        holder.tvNameValue.text = bean.name
        holder.tvRankValue.text = bean.rank.toString()
    }
    

    }

  4. 更新数据集

    private fun resetData() {
        with(mAdapter.mSortedList) {
            beginBatchedUpdates()
            clear()
            // 当SortedList清空数据时,Adapter必须调用notifyDataSetChanged
            // 否则报异常  java.lang.IndexOutOfBoundsException: Inconsistency detected.
            mAdapter.notifyDataSetChanged()
            addAll(mList)
            endBatchedUpdates()
        }
    }
    

Demo地址

DiffUtilDemo

参考文档

  1. SortedList
  2. SortedList.BatchedCallback
  3. SortedList.Callback

猜你喜欢

转载自blog.csdn.net/IO_Field/article/details/79821191