目录
ListAdapter封装 (二)- SimpleAdapter
前言
上一篇文章已经讲解 ListAdapter 的基本使用; 这次我们封装简单条目 SimpleAdapter;
我们使用MVVM模式, 且不再关心实体类型、用Handler 做Item事件回调, 编写统一 DiffCallback
推荐文章
- ListAdapter封装, 告别Adapter代码 (一)- ListAdapter 入门
- ListAdapter封装, 告别Adapter代码 (二)- SimpleAdapter
- ListAdapter封装, 告别Adapter代码 (三)- 头尾,多类型,嵌套,单多选
提示:以下是本篇文章正文内容,下面案例可供参考
一、实体类
1.BaseItem
新建 BaseItem: 列表实体都实现此接口. 它是 BaseAdapter 的默认实体类型
interface BaseItem {
/**
* 条目更新标记, 用于 DiffUtil areContentsTheSame
*/
var hasChanged: Boolean
/**
* 如果 DiffCallback areItemsTheSame() 使用 ID来比较. 则函数返回实体主键.
* 例如: return oldItem.getItemId() == newItem.getItemId()
*/
// fun getItemId(): String
/**
* Adapter 中的 ItemType.
* 单类型布局可以不用重写它
* 多类型布局中; 需直接返回布局Id; 例如: R.layout.item_test
*/
fun getMItemType(): Int = 0
}
2.TestEntity
实体类需要实现 BaseItem; 本类 除了 hasChanged, 就只有一个 title 参数;
class TestEntity(
var title: String? = null,
override var hasChanged: Boolean = false
) : BaseItem
二、DiffCallback
实体类型就用 BaseItem;
class DiffCallback<T : BaseItem>: DiffUtil.ItemCallback<T>() {
/**
* 比较两个条目对象 是否为同一个Item
* 如果是 Paging + Room, 则需要用 oldItem.getItemId() == newItem.getItemId() 方式
*/
override fun areItemsTheSame(oldItem: T, newItem: T): Boolean {
return oldItem === newItem
}
/**
* 再确定为同一条目的情况下; 再去比较 item 的内容是否发生变化;
* 我们使用 状态标识方式; 如果使用 Paging, 则应用 Equals 方式;
* @return true: 代表无变化; false: 有变化;
*/
override fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
return !oldItem.hasChanged
}
}
三、ViewHolder, Handler
1.ViewHolder
ViewHolder 在 Adapter 中起到了 为Item绑定数据, 及缓存控件的作用.
我们加入事件响应 handler; 以及重置状态标记;
open class NewViewHolder(val binding: ViewDataBinding, private val handler: BaseHandler?) : RecyclerView.ViewHolder(binding.root){
open fun bind(item: BaseItem?) {
//重置 状态标记
item?.hasChanged = false
binding.setVariable(BR.item, item)
binding.setVariable(BR.handler, handler)
binding.executePendingBindings()
}
}
2.Handler
- 基类: BaseHandler 它只出现在 Adapter基类中,省的我们写泛型; 要用还得用它的子类
- 子类: Handler 提供具体实体泛型. 供布局文件使用
/**
* item 事件响应基类, 这类什么都不用写
*/
open class BaseHandler
/**
* item 事件响应基类, 需提供具体的实体类泛型;
*/
abstract class Handler<T: BaseItem> : BaseHandler() {
abstract fun onClick(view: View, info: T)
}
四、Adapter
1. BaseAdapter
重头戏: BaseAdapter; 但它却如此简单.
只需要传入 BaseHandler 对象; 并重写 onBindViewHolder 即可;
我还重写了 submitList(); (虽然个人感觉这样不对, 但博主还就踩上这坑了) [机智]
abstract class BaseAdapter<T: BaseItem>(
protected val handler: BaseHandler? = null) :
ListAdapter<T, NewViewHolder>(DiffCallback()) {
override fun onBindViewHolder(holder: NewViewHolder, position: Int) {
holder.bind(getItem(position))
}
/**
* 重写 提交数据方法, 让它必定以新数据集合对象传入;
* 这种方式 只是写法简单. 有时会导致不必要的集合重装.
*/
override fun submitList(list: MutableList<out T>?) {
val newData = mutableListOf<T>()
if (list != null) {
newData.addAll(list)
}
super.submitList(newData)
}
}
2.SimpleAdapter
重头戏中的重头来了 SimpleAdapter:
好吧, 它更简单. 继承 BaseAdapter 并传入 layoutId, 再重写 onCreateViewHolder 即可;
open class SimpleAdapter(
/**
* 布局id;
*/
private val layout: Int,
handler: BaseHandler? = null
) :
BaseAdapter<BaseItem>(handler) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewViewHolder {
return NewViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(parent.context), layout, parent, false
), handler
)
}
}
五、开始使用
封装如此简单, 那我们就开始画页面了。
1.Activity
只需要初始化 Adapter, RecycleView, 并设置数据即可;
//只需要传入 布局id 及 事件响应 Handler
mAdapter = SimpleAdapter(R.layout.item_test_mvvm, object : Handler<TestEntity>(){
override fun onClick(view: View, info: TestEntity) {
Toast.makeText(mActivity, "点了条目", Toast.LENGTH_SHORT).show()
}
})
// DataBinding 懂得都懂 -.-
mDataBind.rvRecycle.let {
it.layoutManager = LinearLayoutManager(mActivity)
it.adapter = mAdapter
}
val data = mutableListOf(TestEntity("第一条"), TestEntity("第一条"), TestEntity("第一条"), TestEntity("第一条"), TestEntity("第一条"))
mAdapter.submitList(data)
2.Layout
好吧,再贴出我的 布局文件:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="item"
type="com.example.kotlinmvpframe.network.entity.TestEntity" />
<variable
name="handler"
type="com.example.kotlinmvpframe.test.testtwo.Handler" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:onClick="@{(view) -> handler.onClick(view, item)}"
android:padding="20dp">
<TextView
android:id="@+id/btn2"
style="@style/tv_base_16_dark"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.title}" />
</LinearLayout>
</layout>
总结
简单列表的 Adapter 就用 SimpleAdapter 即可,
使用MVVM模式 ViewModel 也不用单独定义
我们只需要关心布局写法即可.
上一篇: ListAdapter封装, 告别Adapter代码 (一)- ListAdapter 入门
下一篇: ListAdapter封装, 告别Adapter代码 (三)- 头尾,多类型,嵌套,单多选