超级封装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 只需二三十行代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓修改动画效果--动画差值器TimeI
- 下一篇: 写一个测试工具类,只在debug时运行,