美文网首页
Android 解决 BaseRecyclerViewAdapt

Android 解决 BaseRecyclerViewAdapt

作者: 雁过留声_泪落无痕 | 来源:发表于2021-09-27 11:32 被阅读0次

    一、 背景

    1. 截止本文撰写时,CymChad/BaseRecyclerViewAdapterHelper 为 3.0.6 版本,commit id 为 2813dd1dac57d2e0309c2315f8569e455735c343,且 Demo 处于编译不过的状态(Java 实现了 Kotlin 含默认实现方法的接口,需要使用 @JvmDefault 注解)。

    2. 用过的童鞋应该知道,BaseQuickAdapter 中有个 setOnItemClickListener(OnItemClickListener) 的方法,用于设置 item 的点击回调,但是在回到的地方却需要强制类型转换。
      究其原因,是因为 OnItemClickListener 定义在了一个单独的文件里,并且没有指定泛型。

    public interface OnItemClickListener {
        void onItemClick(@NonNull BaseQuickAdapter<?,?> adapter, @NonNull View view, int position);
    }
    
    1. 看官方的示例代码
    class HomeActivity : AppCompatActivity(), OnItemClickListener {
    
        private lateinit var binding: ActivityHomeBinding
    
        /**
         * RV适配器
         */
        private val homeAdapter by lazy {
            HomeAdapter(homeItemData).apply {
                animationEnable = true
    
                val top = layoutInflater.inflate(R.layout.top_view, binding.recyclerView, false)
                addHeaderView(top)
                setOnItemClickListener(this@HomeActivity)
            }
        }
    
        override fun onItemClick(adapter: BaseQuickAdapter<*, *>, view: View, position: Int) {
            // 这里用到了强制类型转换
            val item = adapter.data[position] as HomeEntity
            if (!item.isHeader) {
                startActivity(Intent(this@HomeActivity, item.activity))
            }
        }
        ...
    }
    

    二、解决方式1:传递泛型给 OnItemClickListener

    1. 给 OnItemClickListener 加上泛型
    public interface OnItemClickListener<T, VH extends BaseViewHolder> {
        void onItemClick(@NonNull BaseQuickAdapter<T, VH> adapter, @NonNull View view, int position);
    }
    
    1. BaseQuickAdapter 中代码也需要修改

    修改前:

    abstract class BaseQuickAdapter<T, VH : BaseViewHolder>
    @JvmOverloads constructor(@LayoutRes private val layoutResId: Int,
                              data: MutableList<T>? = null)
        : RecyclerView.Adapter<VH>() {
        
        private var mOnItemClickListener: OnItemClickListener? = null
        
        fun setOnItemClickListener(listener: OnItemClickListener?) {
            this.mOnItemClickListener = listener
        }
        
        fun getOnItemClickListener(): OnItemClickListener? = mOnItemClickListener
    
    }
    

    修改后:

    abstract class BaseQuickAdapter<T, VH : BaseViewHolder>
    @JvmOverloads constructor(@LayoutRes private val layoutResId: Int,
                              data: MutableList<T>? = null)
        : RecyclerView.Adapter<VH>() {
        
        private var mOnItemClickListener: OnItemClickListener<T, VH>? = null
        
        fun setOnItemClickListener(listener: OnItemClickListener<T, VH>?) {
            this.mOnItemClickListener = listener
        }
        
        fun getOnItemClickListener(): OnItemClickListener<T, VH>? = mOnItemClickListener
    
    }
    
    1. 此时 HomeActivity 中则可以不用强制类型转换了
    class HomeActivity : AppCompatActivity(), OnItemClickListener<HomeEntity, BaseViewHolder> {
    
        private lateinit var binding: ActivityHomeBinding
    
        /**
         * RV适配器
         */
        private val homeAdapter by lazy {
            HomeAdapter(homeItemData).apply {
                animationEnable = true
    
                val top = layoutInflater.inflate(R.layout.top_view, binding.recyclerView, false)
                addHeaderView(top)
                setOnItemClickListener(this@HomeActivity)
            }
        }
    
        override fun onItemClick(adapter: BaseQuickAdapter<HomeEntity, BaseViewHolder>, view: View, position: Int) {
            // 不再需要强制类型转换
            // val item = adapter.data[position] as HomeEntity
            val item = adapter.data[position]
            if (!item.isHeader) {
                startActivity(Intent(this@HomeActivity, item.activity))
            }
        }
        ...
    }
    

    也可以直接以 Lambda 的形式来写:

    class HomeActivity : AppCompatActivity() {
    
        private lateinit var binding: ActivityHomeBinding
    
        /**
         * RV适配器
         */
        private val homeAdapter by lazy {
            HomeAdapter(homeItemData).apply {
                animationEnable = true
    
                val top = layoutInflater.inflate(R.layout.top_view, binding.recyclerView, false)
                addHeaderView(top)
                setOnItemClickListener { adapter, view, position ->
                    // 不再需要强制类型转换
                    // val item = adapter.data[position] as HomeEntity
                    val item = adapter.data[position]
                    if (!item.isHeader) {
                        startActivity(Intent(this@HomeActivity, item.activity))
                    }
                }
            }
        }
        ...
    }
    

    三、解决方式2:不使用 OnItemClickListener 类

    1. 不再使用 OnItemClickListener 类,而是以 Lambda 的形式来定义 BaseQuickAdapter#mOnItemClickListener

    修改前:

    abstract class BaseQuickAdapter<T, VH : BaseViewHolder>
    @JvmOverloads constructor(@LayoutRes private val layoutResId: Int,
                              data: MutableList<T>? = null)
        : RecyclerView.Adapter<VH>() {
        
        private var mOnItemClickListener: OnItemClickListener? = null
        
        protected open fun setOnItemClick(v: View, position: Int) {
            // 通过这里回调出去
            mOnItemClickListener?.onItemClick(this, v, position)
        }
    
        fun setOnItemClickListener(listener: OnItemClickListener?) {
            this.mOnItemClickListener = listener
        }
        
        fun getOnItemClickListener(): OnItemClickListener? = mOnItemClickListener
    
    }
    

    修改后:

    abstract class BaseQuickAdapter<T, VH : BaseViewHolder>
    @JvmOverloads constructor(@LayoutRes private val layoutResId: Int,
                              data: MutableList<T>? = null)
        : RecyclerView.Adapter<VH>() {
        
        private var mOnItemClickListener: ((BaseQuickAdapter<T, VH>, View, Int) -> Unit)? = null
        
        protected open fun setOnItemClick(v: View, position: Int) {
            // 通过这里回调出去
            mOnItemClickListener?.invoke(this, v, position)
        }
        
        fun setOnItemClickListener(listener: ((BaseQuickAdapter<T, VH>, View, Int) -> Unit)?) {
            this.mOnItemClickListener = listener
        }
        
        fun getOnItemClickListener() = mOnItemClickListener
    
    }
    
    1. 此时 HomeActivity 中则可以不用强制类型转换了
    class HomeActivity : AppCompatActivity() {
    
        private lateinit var binding: ActivityHomeBinding
    
        /**
         * RV适配器
         */
        private val homeAdapter by lazy {
            HomeAdapter(homeItemData).apply {
                animationEnable = true
    
                val top = layoutInflater.inflate(R.layout.top_view, binding.recyclerView, false)
                addHeaderView(top)
                setOnItemClickListener { adapter, view, position ->
                    // 不再需要强制类型转换
                    // val item = adapter.data[position] as HomeEntity
                    val item = adapter.data[position]
                    if (!item.isHeader) {
                        startActivity(Intent(this@HomeActivity, item.activity))
                    }
                }
            }
        }
        ...
    }
    

    当然,也可以在类上声明实现这个接口:

    class HomeActivity : AppCompatActivity(),
            (BaseQuickAdapter<HomeEntity, BaseViewHolder>, View, Int) -> Unit {
    
        private lateinit var binding: ActivityHomeBinding
    
        /**
         * RV适配器
         */
        private val homeAdapter by lazy {
            HomeAdapter(homeItemData).apply {
                animationEnable = true
    
                val top = layoutInflater.inflate(R.layout.top_view, binding.recyclerView, false)
                addHeaderView(top)
                setOnItemClickListener(this@HomeActivity)
            }
        }
    
        override fun invoke(
            adapter: BaseQuickAdapter<HomeEntity, BaseViewHolder>,
            view: View,
            position: Int
        ) {
            // 不再需要强制类型转换
            // val item = adapter.data[position] as HomeEntity
            val item = adapter.data[position]
            if (!item.isHeader) {
                startActivity(Intent(this@HomeActivity, item.activity))
            }
        }
        ...
    }
    

    四、最后

    鼓掌.png

    相关文章

      网友评论

          本文标题:Android 解决 BaseRecyclerViewAdapt

          本文链接:https://www.haomeiwen.com/subject/jzyhnltx.html