超级封装RecyclerView的适配器Adapter 只需二三十行代码
前言
android開(kāi)發(fā)中,RecyclerView是很常用的控件,而且功能也很強(qiáng)大,并且各種三方封裝或者擴(kuò)展庫(kù)也是非常多,如:BaseQuickAdapter,XRecyclerview,當(dāng)然還有我以前封裝的LtRecyclerView
比如BaseQuickAdapter雖然封裝的非常方便,但那是相對(duì)于java語(yǔ)言,那用kotlin能不能使Adapter的封裝更方便呢?答案是可以
第一次簡(jiǎn)單封裝
/*** 封裝適配器,適用于單條目** @param T bean類(lèi)的泛型* @param VH ViewHolder的泛型*/ abstract class BaseAdapterOneType<T, VH : RecyclerView.ViewHolder>(val list: MutableList<T>) : RecyclerView.Adapter<VH>() {/*** 給view設(shè)置數(shù)據(jù)*/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 }使用起來(lái)需要繼承該類(lèi),并重寫(xiě)setData方法和寫(xiě)一個(gè)ViewHolder,如下:
fun initView(){.....rv.adapter = MainAdapter(arrayListOf())//設(shè)置適配器}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))//設(shè)置布局override fun setData(b: String, i: Int, h: MainAdapterVH) {//設(shè)置數(shù)據(jù)h.tv.text = b}}class MainAdapterVH(val v: View) : RecyclerView.ViewHolder(v) {//查找Viewval tv = v.tv1}但是這樣和java差不多,寫(xiě)起來(lái)還是比較麻煩
第二次封裝,簡(jiǎn)少所需代碼
abstract class BaseAdapterOneType3<T>(val list: MutableList<T>, @LayoutRes val layoutId: Int) : RecyclerView.Adapter<BaseViewHolder>() {/*** 給view設(shè)置數(shù)據(jù)*/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)使用起來(lái)就很方便了,只需要重寫(xiě)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來(lái)查找控件v.tv1.text = b}}這樣封裝后用起來(lái)就方便的多了
等等,你以為這樣就結(jié)束了嗎?看性能!
我們來(lái)看一下MainAdapter編譯后的字節(jié)碼做了什么
ps:通過(guò)Koltin自帶的插件,然后點(diǎn)擊Decompile按鈕來(lái)還原成java代碼
如下:
首先構(gòu)造和下面的泛型轉(zhuǎn)換的setData方法不用看,檢查Null的也不用看,主要看下面兩行
TextView var10000 = (TextView)v.findViewById(id.tv1); var10000.setText((CharSequence)b);通過(guò)上面的代碼會(huì)發(fā)現(xiàn),每次走setData(onBindViewHolder)都會(huì)進(jìn)行findViewById,如果是一個(gè)經(jīng)常滾動(dòng)的列表,則會(huì)頻繁的調(diào)用setData方法,則沒(méi)有用到RecyclerView.ViewHolder,效率變低
中間我想過(guò),參考Activity的方式在公用的ViewHolder里維護(hù)一個(gè)HashMap<Int,View>,并提供一個(gè)get方法,但是這樣跟BaseQuickAdapter的寫(xiě)法就一樣了,比較繁瑣,pass
后來(lái)又想,通過(guò)by委托給一個(gè)類(lèi),讓其存儲(chǔ)鍵值對(duì)和泛型信息,但是后來(lái)發(fā)現(xiàn)并不行,直到有一次靈光一現(xiàn)!
第三次封裝,既少寫(xiě)代碼又性能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的框架來(lái)快捷查找view,并且?guī)в芯彺?/class ViewFind : Fragment() {private lateinit var mView: Viewfun setView(view: View) {this.mView = view}override fun getView(): View? {return mView}} }實(shí)現(xiàn)思路,有一次我想,既然Fragment中能用Kotlin的框架直接來(lái)findViewById,那能不能找找是從哪個(gè)方法獲取父View的,然后發(fā)現(xiàn)原來(lái)是getView這個(gè)方法,而且還可以進(jìn)行復(fù)寫(xiě),于是就給RecyclerView.ViewHolder的itemView加了一層Fragment,然后在setData中用Fragment來(lái)查找View,這樣既寫(xiě)著方便,并且在Fragment中還有緩存(Kotlin框架的實(shí)現(xiàn)),簡(jiǎn)直完美
使用方法如下:
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) {//在這里直接通過(guò)Fragment來(lái)查找View,并設(shè)置屬性v.tv1.text = b}}并且查看編譯后的代碼確實(shí)有緩存:
ps:后來(lái)發(fā)現(xiàn)可以使用LayoutContainer,性能可以更好,可以參考https://github.com/ltttttttttttt/ltviews里的ltviewsx里的BaseAdapterOneType和BaseLtViewHolder
利用IDEA的Live Templates來(lái)快捷生成代碼
有的同學(xué)說(shuō),還是很多樣板代碼,不想寫(xiě)怎么辦,emmm...有的辦,使用Live Templates
打開(kāi)設(shè)置,根據(jù)圖的步驟添加
起一個(gè)名字,然后說(shuō)明用途,并粘貼進(jìn)入以下代碼
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
然后點(diǎn)擊右邊的Edit variables按鈕,設(shè)置成如下圖的樣子
然后新建一個(gè)Kotlin File,在空白處輸入badapter,就會(huì)自動(dòng)生成實(shí)現(xiàn)類(lèi),填入泛型和layoutId后就可以開(kāi)心的用了
結(jié)語(yǔ)
emmm,好了,封裝結(jié)束,小伙伴們可以直接復(fù)制最后一種封裝方式,然后快樂(lè)的用RecyclerView編碼了
當(dāng)然,如果用的是別人封裝過(guò)的adapter,也可以使用該方式進(jìn)行二次封裝,可以書(shū)寫(xiě)更方便
RecyclerView.Adapter還能在簡(jiǎn)化或優(yōu)化性能嗎?其實(shí)還有存貨,不過(guò)等下次有時(shí)間了在寫(xiě)吧 \滑稽
總結(jié)
以上是生活随笔為你收集整理的超级封装RecyclerView的适配器Adapter 只需二三十行代码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 安卓修改动画效果--动画差值器TimeI
- 下一篇: 写一个测试工具类,只在debug时运行,