一晃五六年,歲月蹉跎,不由感嘆:曾幾什麼時候,沉迷於框架不能自拔,無論作什麼需求都要找一個框架出來,而後用了一段時間後,發現諸多問題,不少時候又不得不將就着用,難道咱們就應該被別人左右嗎?答案是No,仍是得試着提升本身的架構能力,來應對將來更多的挑戰。你越是醒悟的快,你的進步就會越快,閱讀源碼是痛苦的,可愈來愈多的痛苦終將會成就你,不信你跟着我往下看。緩存
名字 | Star | 未解決問題 | 最後一次更新時間 | 包大小(aar) |
---|---|---|---|---|
BaseRecyclerViewAdapterHelper | 20.2k | 162 | 27天前 | 81KB (V2.9.5) |
baseAdapter | 4.5K | 107 | 4年前 | 10.53 KB (v3.0.3) |
FlexibleAdapter | 3.3K | 55 | 15個月前 | 123KB (v5.0.5) |
FastAdapter | 3.1K | 3 | 8天前 | 164KB (v5.1.0) |
經過這些基礎數據的比較,讓你選擇,你會怎麼選?固然首先會剔除掉baseAdapter、FlexibleAdapter,一年以上不維護,問題50個以上,框架底子再好,選擇之後就要靠本身了不是,咱們再來看問題最少更新最頻繁的是FastAdapter,可它的包足足大了BaseRecyclerViewAdapterHelper一倍,請問做者你幹了哈,要這麼大的嗎?若是大家公司對包大小有要求,這個基本被pass了,可能你以爲164KB不大,可若是再多幾個框架,疊加起來也會大啊,能省則省唄。看來最合適的只有BaseRecyclerViewAdapterHelper,可它的問題又是最多,太難了,一點也不簡單。不如本身作一個算了,對了,咱們仍是選擇本身搞一個唄。架構
之前咱們的實現,要分別實現Adapter、ViewHolder、Model,並且它們之間耦合嚴重,遇到一個複雜的列表真是苦不堪言。app
如今咱們要實現以下目標框架
class DefaultViewHolder(val view: View) : RecyclerView.ViewHolder(view) { /** * views緩存 */ private val views: SparseArray<View> = SparseArray() val mContext: Context = view.context fun <T : View> getView(@IdRes viewId: Int): T? { return retrieveView(viewId) } private fun <T : View> retrieveView(@IdRes viewId: Int): T? { var view = views[viewId] if (view == null) { view = itemView.findViewById(viewId) if (view == null) return null views.put(viewId, view) } return view as T } }
ViewHolder職責很單一,就是負責持有View的引用,輔助你用對的View作對的事,這裏優化了一點就是用到SparseArray緩存,其實就是作了簡單的優化,防止再次findViewById形成沒必要要的損耗。BaseRecyclerViewAdapterHelper的ViewHolder也是用的這個實現,這是你們公認的比較靠譜的寫法。ide
ViewModel這層很關鍵,它負責View數據的綁定邏輯和負責加載哪一個Layout,來直接看代碼佈局
public abstract class ViewModel<M, VH extends RecyclerView.ViewHolder> { public M model; public VH viewHolder; public abstract void onBindView(RecyclerView.Adapter<?> adapter); int getItemViewType() { return getLayoutRes(); } @LayoutRes public abstract int getLayoutRes(); }
這麼設計最大的亮點就是少了ItemViewType的維護,讓你看看別人的設計,下面是別人的代碼,維護ItemViewType,嚇人不,若是之後再多一種EMPTY_VIEW,那我是否是得擴展一個EMPTY_VIEW2啊,並且還要修改這裏的邏輯,這麼設計不科學啊,應該永遠或者說盡可能不要動底層邏輯纔對,由於你動了底層邏輯就要面臨的全面測試。
在我看來,最好的設計是永遠不要關心ItemViewType的邏輯,而所謂的頭部View和底部View只是你維護在List頂端和低端的數據,最終根據List的排序綁定到ItemView上,而不是經過ItemViewType去控制,這點你細細品味。而EmptyView更像是一個壓在RecyclerView上面的棧,或者你把List改爲一個Empty的ViewModel並全屏展現的RecyclerView上,當有真實數據的時候將其移除掉,總之咱們操做的就是ViewModel的去和留,保持Adapter底層邏輯的簡潔。測試
史上最簡單的通用Adapter就要出現了,鼓掌把朋友優化
abstract class ListAdapter<VM : ViewModel<*, *>> : RecyclerView.Adapter<DefaultViewHolder>() { protected val layouts: SparseIntArray by lazy(LazyThreadSafetyMode.NONE) { SparseIntArray() } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DefaultViewHolder { return DefaultViewHolder(LayoutInflater.from(parent.context).inflate(layouts[viewType], parent, false)) } override fun getItemViewType(position: Int): Int { val item = getItem(position) layouts.append(item.itemViewType, item.layoutRes) return item.itemViewType } override fun onBindViewHolder(holder: DefaultViewHolder, position: Int) { val item = getItem(position) item.onBindView(this) } abstract fun getItem(position: Int): VM } class ArrayListAdapter<M> : ListAdapter<ArrayListViewModel<M>>() { private val observableDataList = ObservableArrayList<ArrayListViewModel<M>>() init { observableDataList.addOnListChangedCallback(object : OnListChangedCallback<ObservableArrayList<ArrayListViewModel<M>>>() { override fun onChanged(sender: ObservableArrayList<ArrayListViewModel<M>>) { notifyDataSetChanged() } override fun onItemRangeChanged(sender: ObservableArrayList<ArrayListViewModel<M>>, positionStart: Int, itemCount: Int) { notifyItemRangeChanged(positionStart, itemCount) } override fun onItemRangeInserted(sender: ObservableArrayList<ArrayListViewModel<M>>, positionStart: Int, itemCount: Int) { notifyItemRangeInserted(positionStart, itemCount) } override fun onItemRangeMoved(sender: ObservableArrayList<ArrayListViewModel<M>>, fromPosition: Int, toPosition: Int, itemCount: Int) { notifyItemMoved(fromPosition, toPosition) } override fun onItemRangeRemoved(sender: ObservableArrayList<ArrayListViewModel<M>>, positionStart: Int, itemCount: Int) { notifyItemRangeRemoved(positionStart, itemCount) } }) } override fun getItem(position: Int): ArrayListViewModel<M> { return observableDataList[position] } override fun getItemCount(): Int { return observableDataList.size } fun add(index: Int, element: ArrayListViewModel<M>) { observableDataList.add(index, element) } fun removeAt(index: Int): ArrayListViewModel<M> { return observableDataList.removeAt(index) } fun set(index: Int, element: ArrayListViewModel<M>): ArrayListViewModel<M> { return observableDataList.set(index, element) } }
70多行代碼搞定,超級簡單把。this
ListAdapter 抽象類spa
ArrayListAdapter
貼圖不復制類名可恥(我沒作到,你呢?):
CallbackRegistry ListChangeRegistry ObservableList ObservableArrayList
abstract class ArrayListViewModel<M> : ViewModel<M, DefaultViewHolder>() { override fun onBindView(adapter: RecyclerView.Adapter<*>?) { onBindAdapter(adapter = adapter as ArrayListAdapter<M>) } abstract fun onBindAdapter(adapter: ArrayListAdapter<M>) }
這裏是爲了讓ArrayListAdapter對象傳遞給ArrayListViewModel的onBindView,讓對應的ViewModel,來看個實現就知道了,下面就是個例子,這裏能夠直接拿到ArrayListAdapter對象,這樣就能夠作對應Adapter的操做,不然你就要用ListAdapter,用的時候可能會須要強轉,可你強轉的對不對呢?增長了不肯定因素,因此這裏在抽象類實現,你要明白,抽象的目的就是爲了肯定性,是吧。
class ReportEditorViewModel : ArrayListViewModel<ReportEditorBean>(){ override fun onBindAdapter(adapter: ArrayListAdapter<ReportEditorBean>) { } override fun getLayoutRes(): Int { return R.layout.item_report_editor_house } }
因爲kotlin的便利,咱們還須要擴展一下RecyclerView,如代碼:
fun <VM : ViewModel<*,*>> RecyclerView.bindListAdapter(listAdapter: ListAdapter<VM>,layoutManager: RecyclerView.LayoutManager? = null){ this.layoutManager = layoutManager?: LinearLayoutManager(context) this.adapter = listAdapter }
給如今的RecyclerView擴展bindListAdapter,並傳入咱們本身的抽象ListAdapter,最終綁定到一塊兒。並提供layoutManager的默認配置,減小模版代碼的生成。
val adapter = ArrayListAdapter<ReportEditorBean>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_report_editor) rv_house_list.bindListAdapter(adapter) adapter.add(ReportEditorViewModel()) adapter.add(ReportEditorViewModel()) }
一個Adapter、一個RecyclerView,而後就是Adapter負責增刪改。就這麼簡單。
顛覆你認知的時候又到了,請你忘記對Adapter的擴展實現一個onItemClickCallBack,太愚蠢了。答案就在咱們的ViewModel裏,看代碼實現
class ReportEditorViewModel : ArrayListViewModel<ReportEditorBean>(){ override fun onBindAdapter(adapter: ArrayListAdapter<ReportEditorBean>) { viewHolder.view.setOnClickListener { } } override fun getLayoutRes(): Int { return R.layout.item_report_editor_house } }
在ViewModel的實現裏,用viewHolder不就能夠自子加點擊事件嗎?並且不一樣的ViewModel,點擊事件處理也均可以不同,你還用在onItemClickCallBack裏判斷點擊是什麼怎麼處理嗎?那種愚蠢的設計就拋棄吧。
今天帶你實現了一個超級的Adapter,行嗎?以爲Ok,麻煩辛苦下你的小手,點個贊哦親。