欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

超级封装RecyclerView的适配器Adapter 只需二三十行代码

发布时间:2025/3/21 编程问答 70 豆豆
生活随笔 收集整理的这篇文章主要介绍了 超级封装RecyclerView的适配器Adapter 只需二三十行代码 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

前言

android开发中,RecyclerView是很常用的控件,而且功能也很强大,并且各种三方封装或者扩展库也是非常多,如:BaseQuickAdapter,XRecyclerview,当然还有我以前封装的LtRecyclerView

比如BaseQuickAdapter虽然封装的非常方便,但那是相对于java语言,那用kotlin能不能使Adapter的封装更方便呢?答案是可以

第一次简单封装

/*** 封装适配器,适用于单条目** @param T bean类的泛型* @param VH ViewHolder的泛型*/ abstract class BaseAdapterOneType<T, VH : RecyclerView.ViewHolder>(val list: MutableList<T>) : RecyclerView.Adapter<VH>() {/*** 给view设置数据*/abstract fun setData(b: T, i: Int, h: VH)override fun onBindViewHolder(holder: VH, position: Int) = setData(list[position], position, holder)override fun getItemCount() = list.size }

使用起来需要继承该类,并重写setData方法和写一个ViewHolder,如下:

fun initView(){.....rv.adapter = MainAdapter(arrayListOf())//设置适配器}class MainAdapter(list: MutableList<String>) : BaseAdapterOneType<String, MainAdapterVH>(list) {override fun onCreateViewHolder(p0: ViewGroup, p1: Int): MainAdapterVH = MainAdapterVH(LayoutInflater.from(p0.context).inflate(R.layout.item_pop_text, p0, false))//设置布局override fun setData(b: String, i: Int, h: MainAdapterVH) {//设置数据h.tv.text = b}}class MainAdapterVH(val v: View) : RecyclerView.ViewHolder(v) {//查找Viewval tv = v.tv1}

但是这样和java差不多,写起来还是比较麻烦

第二次封装,简少所需代码

abstract class BaseAdapterOneType3<T>(val list: MutableList<T>, @LayoutRes val layoutId: Int) : RecyclerView.Adapter<BaseViewHolder>() {/*** 给view设置数据*/abstract fun setData(v: View, b: T, i: Int, h: BaseViewHolder)override fun onBindViewHolder(holder: BaseViewHolder, position: Int) = setData(holder.itemView, list[position], position, holder)override fun getItemCount() = list.sizeoverride fun onCreateViewHolder(p0: ViewGroup, p1: Int): BaseViewHolder = BaseViewHolder(LayoutInflater.from(p0.context).inflate(layoutId, p0, false)) }class BaseViewHolder(private val view: View) : RecyclerView.ViewHolder(view)

使用起来就很方便了,只需要重写setData方法,如下:

fun initView(){...rv.adapter = MainAdapter(arrayListOf())}class MainAdapter(list: MutableList<String>) : BaseAdapterOneType3<String>(list, R.layout.item_pop_text) {override fun setData(v: View, b: String, i: Int, h: BaseViewHolder) {//利用Kotlin的特性,直接使用id来查找控件v.tv1.text = b}}

这样封装后用起来就方便的多了

等等,你以为这样就结束了吗?看性能!

我们来看一下MainAdapter编译后的字节码做了什么

ps:通过Koltin自带的插件,然后点击Decompile按钮来还原成java代码

如下:

首先构造和下面的泛型转换的setData方法不用看,检查Null的也不用看,主要看下面两行

TextView var10000 = (TextView)v.findViewById(id.tv1); var10000.setText((CharSequence)b);

通过上面的代码会发现,每次走setData(onBindViewHolder)都会进行findViewById,如果是一个经常滚动的列表,则会频繁的调用setData方法,则没有用到RecyclerView.ViewHolder,效率变低

中间我想过,参考Activity的方式在公用的ViewHolder里维护一个HashMap<Int,View>,并提供一个get方法,但是这样跟BaseQuickAdapter的写法就一样了,比较繁琐,pass

后来又想,通过by委托给一个类,让其存储键值对和泛型信息,但是后来发现并不行,直到有一次灵光一现!

第三次封装,既少写代码又性能ok

abstract class BaseLtAdapterOneType<T>(var list: MutableList<T>, @LayoutRes private val itemLayoutId: Int) : RecyclerView.Adapter<BaseLtViewHolder>() {abstract fun setData(v: BaseLtViewHolder.ViewFind, b: T, i: Int, h: BaseLtViewHolder)override fun onBindViewHolder(holder: BaseLtViewHolder, position: Int) = setData(holder.viewFind, list[position], position, holder)override fun getItemCount() = list.sizeoverride fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = BaseLtViewHolder(parent.inflate(itemLayoutId)) }/*** 使用方便的ViewHolder*/ class BaseLtViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {val viewFind: ViewFind = ViewFind().apply { this.setView(this@BaseLtViewHolder.view) }/*** 使用kt的框架来快捷查找view,并且带有缓存*/class ViewFind : Fragment() {private lateinit var mView: Viewfun setView(view: View) {this.mView = view}override fun getView(): View? {return mView}} }

实现思路,有一次我想,既然Fragment中能用Kotlin的框架直接来findViewById,那能不能找找是从哪个方法获取父View的,然后发现原来是getView这个方法,而且还可以进行复写,于是就给RecyclerView.ViewHolder的itemView加了一层Fragment,然后在setData中用Fragment来查找View,这样既写着方便,并且在Fragment中还有缓存(Kotlin框架的实现),简直完美

使用方法如下:

fun initView(){...rv.adapter = MainAdapter(arrayListOf())}class MainAdapter(list: MutableList<String>) : BaseLtAdapterOneType<String>(list, R.layout.item_pop_text) {override fun setData(v: BaseLtViewHolder.ViewFind, b: String, i: Int, h: BaseLtViewHolder) {//在这里直接通过Fragment来查找View,并设置属性v.tv1.text = b}}

并且查看编译后的代码确实有缓存:

ps:后来发现可以使用LayoutContainer,性能可以更好,可以参考https://github.com/ltttttttttttt/ltviews里的ltviewsx里的BaseAdapterOneType和BaseLtViewHolder

利用IDEA的Live Templates来快捷生成代码

有的同学说,还是很多样板代码,不想写怎么办,emmm...有的办,使用Live Templates

打开设置,根据图的步骤添加

起一个名字,然后说明用途,并粘贴进入以下代码

class $className$(list: MutableList<$T$>) : BaseLtAdapterOneType<$T$>(list, R.layout.$next$) {override fun setData(v: BaseLtViewHolder.ViewFind, b: $T$, i: Int, h: BaseLtViewHolder) {$code$} }

按照下面图示勾上Kotlin

然后点击右边的Edit variables按钮,设置成如下图的样子

然后新建一个Kotlin File,在空白处输入badapter,就会自动生成实现类,填入泛型和layoutId后就可以开心的用了

结语

emmm,好了,封装结束,小伙伴们可以直接复制最后一种封装方式,然后快乐的用RecyclerView编码了

当然,如果用的是别人封装过的adapter,也可以使用该方式进行二次封装,可以书写更方便

RecyclerView.Adapter还能在简化或优化性能吗?其实还有存货,不过等下次有时间了在写吧 \滑稽

总结

以上是生活随笔为你收集整理的超级封装RecyclerView的适配器Adapter 只需二三十行代码的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。