Android 解决 BaseRecyclerViewAdapt

2021-09-27  本文已影响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
上一篇下一篇

猜你喜欢

热点阅读