在最新的 recyclerview:1.2.0-alpha02 中發佈了一個關於 Adapter 的新特性 MergeAdapter 。咱們能夠 「合併」Adapter,或者說給 Adapter 「作加法」。java
聽起來可能不是那麼容易理解。咱們先來看下面的 RecyclerView 應該如何實現?android
源碼地址見文末。git
實現起來其實很簡單,利用現有的知識,大部分人都能想到用多類型的 itemView 。這裏要區分三種類型,Teacher ,Student 和 Foot 。不一樣的類型要對應不一樣的佈局文件,一樣也對應不一樣的業務邏輯。github
長久以來咱們一直都是這麼作的。那麼,你有沒有想過這麼作有什麼不合理的地方嗎?耦合度太高 。上面的示例中一個 Adapter 須要負責三套視圖佈局的呈現,若是是四套,五套,甚至更多呢?從 擴展性 上來講,這個方案也不盡合理。設計模式
既然如此,那就讓每一個 Adapter 只負責一套視圖佈局。既下降了代碼耦合度,又便於擴展。若是出現了新的佈局類型,再來一個 Adapter 就好了。上面的示例中一共須要三個 Adapter,TeahcherAdapter
,StudentAdapter
,FootAdapter
。ide
TeahcherAdapter
負責展現列表最上面 Teacher 部分的視圖。 StudentAdapter
負責展現列表主體 Student 部分的視圖。 FootAdapter
負責展現列表底部加載狀態的視圖,包含加載中和無更多數據。函數
看起來很美好,各司其職,互不干擾。然而問題時,你的 RecyclerView 能夠接受幾個 Adapter ?佈局
public void setAdapter(@Nullable Adapter adapter) {
// bail out if layout is frozen
setLayoutFrozen(false);
setAdapterInternal(adapter, false, true);
processDataSetCompletelyChanged(false);
requestLayout();
}
複製代碼
RecyclerView 顯然是 「一夫一妻制」 。經過 setAdapter()
方法,咱們只能給 RecyclerView 設置一個 Adapter 。post
在 recyclerview:1.2.0-alpha02 中,其實咱們仍然只能設置一個 Adapter ,可是這個 Adapter 能夠是 MergeAdapter ,一個能夠作加法的 Adapter 。學習
直接上代碼。
private val teacherAdapter by lazy { TeacherAdapter() }
private val studentAdapter by lazy { StudentAdapter() }
private val stateAdapter by lazy { StateAdapter() }
val mergeAdater = MergeAdapter(teacherAdapter, studentAdapter, footAdapter)
recyclerView.adapter = mergeAdapter
複製代碼
使用方法就是如此的樸實無華,甚至有那麼一點枯燥。MergeAdapter 構造函數中的參數順序,就標識了列表中數據的顯示順序。
第一塊佈局是 Teacher 。在實際開發中,經常能夠用做 Header View 。
class TeacherAdapter : ListAdapter<Teacher, TeacherViewHolder>(TeacherDiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TeacherViewHolder {
return TeacherViewHolder(
ItemTeacherBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: TeacherViewHolder, position: Int) {
holder.bind(getItem(position))
}
}
複製代碼
第二塊佈局是 Student 。也就是實際開發中的真正的列表數據。
class StudentAdapter : ListAdapter<Student, StudentViewHolder>(StudentDiffCallBack()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StudentViewHolder {
return StudentViewHolder(
ItemStudentBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: StudentViewHolder, position: Int) {
holder.bind(getItem(position))
}
}
複製代碼
最後一塊佈局是狀態佈局,也就是一般的 Footer 。包含正在加載,加載失敗和無更多數據,三種狀態。
class FootAdapter : ListAdapter<LoadState, StateViewHolder>(StateDiffCallBack()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StateViewHolder {
return StateViewHolder(
ItemStateBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: StateViewHolder, position: Int) {
holder.bind(getItem(position))
}
}
複製代碼
和日常的 Adapter 寫法並沒有二致。
衆所周知,RecyclerView 是一個設計極其精妙的類庫,從源碼裏能夠發現不少設計模式的身影。MergeAdapter 也不例外。
將一個 Adapter 負責多套佈局,拆分爲每一個 Adapter 只處理一個佈局,大大下降代碼耦合,這是 單一職責原則 。
面對新的需求,須要給 RecyclerView 增長一個新類型的 View。咱們須要作的僅僅只是添加新的 Adapter ,而無需修改以前的適配器代碼。對擴展開放,對修改封閉,這是 開閉原則 。
如上面的例子所示,MergeAdapter 的數據展現順序,是按照構造函數中的參數順序依次排列的,並且同類型的數據老是集中展現的。因此,對於不肯定性的,動態類型的複雜視圖,MergeAdapter 是沒法處理的。
另外說一點,稱不上限制,應該說對 MergeAdapter 能力的指望。若是能支持多 LayoutManager 那就更好了。在多類型 RecyclerView 中,部分數據須要橫向滑動展現,部分數據須要縱向滑動展現,這種狀況已經比較常見了。
MergeAdapter 的一些學習資源。
Android 開發團隊的相關介紹:
掘金譯文:
文中示例源碼地址:
這裏是秉心說,歡迎關注個人公衆號,第一時間爲你帶來 Android 最新動態。