使用更少代碼的ListAdapter

寫在前面的話

在項目中,咱們常常用到列表,在之前咱們使用RecyclerView,伴隨着確定會有一個繼承RecyclerView.Adapter的adapter 可是在這個adapter中,可是這個adapter中,咱們會寫較多的代碼。在com.android.support:recyclerview-v7:27.1.0 中增長了一個ListAdapter,這個ListAdapter讓咱們使用起來更加方便。java

存在的問題

在之前咱們是經過這樣的方式來進行處理android

class TestAdapter<T> : RecyclerView.Adapter<TestAdapter.ViewHolder<T>>() {

    var TAG = "ADAPTER"

    var mData: MutableList<T> = ArrayList()


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder<T> {
        val inflater = LayoutInflater.from(parent.context)
        return TestAdapter.ViewHolder(inflater.inflate(R.layout.item_user, parent, false))
    }

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

    override fun onBindViewHolder(holder: ViewHolder<T>, position: Int) {

        holder.bind(mData[position])
    }


    fun add(t: T) {
        if (t != null) {
            mData.add(t)
        } else {
            Log.e(TAG, "the data is null")
        }
        notifyDataSetChanged()
    }


    fun addList(@NonNull ts: List<T>) {
        mData.clear()
        mData.addAll(0, ts)
        notifyDataSetChanged()
    }

    fun appendList(@NonNull ts: List<T>) {

        mData.addAll(mData.size, ts)
        notifyDataSetChanged()
    }
    
    fun deleteItem(position: Int){
        if (mData.size > position){
            mData.removeAt(position)
        }
       notifyDataSetChanged()
    }

   

    class ViewHolder<T>(itemView: View) : RecyclerView.ViewHolder(itemView) {

        fun bind(t: T) {

        }

    }

}

複製代碼

咱們大概都會作相似以上的一種事情,可是裏面有一個最大的問題,那就是不管是增長(add) 仍是刪除,都須要咱們本身處理,處理後咱們會調用notifyDataSetChanged()方法進行刷新。 可是刷新以後咱們會發現RecyclerView的動畫消失了。固然爲了解決這個問題,咱們能夠調用如下方法:app

  • adapter.notifyItemRangeInserted(position, count);
  • adapter.notifyItemRangeRemoved(position, count);
  • adapter.notifyItemMoved(fromPosition, toPosition);
  • adapter.notifyItemRangeChanged(position, count, payload);

這四種方法是帶動畫。 還有一種解決方式就是使用DiffUtilide

DiffUtil

DiffUtil在 support library 25.1.0 的時候就引入了,最主要的功能就是處理adapter的更新,其功能 就是比較兩個數據集,用newList和oldList進行比較,得出最小的變化量。也就是說咱們不須要再無腦的使用 notifyDataSetChanged()。也就是說若是咱們使用了DiffUtil,那麼咱們不須要去區別上述的四種調用方式, DiffUtil將自動爲咱們處理而後進行調用。函數

DiffUtil.ItemCallback

ListAdapter的構造函數中,咱們須要一個DiffUtil的回調,固然咱們通常就使用DiffUtil.ItemCallback動畫

class UserDiffCallback : DiffUtil.ItemCallback<User>() {

    override fun areItemsTheSame(oldItem: User?, newItem: User?): Boolean {
        return oldItem?.userId == newItem?.userId
    }

    override fun areContentsTheSame(oldItem: User?, newItem: User?): Boolean {
        return oldItem == newItem
    }
}
複製代碼

如上,咱們需重寫其中的兩個方法areItemsTheSameareContentsTheSamespa

areItemsTheSame

areItemsTheSame提供了兩個對象,需你提供這個兩個對象是不是同一個對象。在User對象中有一個userId, 其表明了惟一性,因此這裏我就使用了oldItem?.userId == newItem?.userId。這個可根據實際狀況自行判斷。code

areContentsTheSame

areContentsTheSame也提供了兩個對象,而後須要你提供這個兩個對象的內容是否一致,若是不一致,那麼 它就將對列表進行重繪和動畫加載,反之,表示你已經顯示了這個對象的內容而且沒有任何的變化, 那麼將不作任何的操做。對象

ListAdapter

與以前的adapter沒有太多的區別,就是去掉了咱們的數據列表mData和不在使用notifyDataSetChanged相關 方法。繼承

class UserAdapter : ListAdapter<User, RecyclerView.ViewHolder>(UserDiffCallback()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        return UserAdapter.ViewHolder(inflater.inflate(R.layout.item_user, parent, false))
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        if (holder is ViewHolder) {
            holder.bind(getItem(position))
        }
    }


    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(user: User) {
            
        }
    }

}
複製代碼

其實就是一個很簡單的Adapter,不須要任增長任何新的方法(增、刪、改),不管是增長仍是更新或者刪除, 咱們只須要使用adapter.submitList(List)方法

可是須要注意一個問題,這個adapter.submitList(List)方法中須要提供一個列表,這個List必須是一個新的 列表,也就是說,若是你使用的是一個已經加載了的列表,那麼將不會被加載。

總結

ListAdapter讓開發着使用更少的代碼,而且可以讓用戶擁有視覺上的享受

相關文章
相關標籤/搜索