Closed sablib closed 3 years ago
感谢建议,其实 MultiType 旧版曾经提供了 flatten adapter 来进行 item map,后来由于诸多原因,其中最主要的原因是,使得 item 和 binder 映射关系变得隐秘,失去了简单性和直观性,因此此功能已经被删除了。不过你的再度提议也有道理,可以考虑。
根据你的建议,map 动作在注册链中,可以一定程度缓解映射直观性下降问题,十分不错的建议,近期如果有时间,我们可以实现一个版本看看。
你好,我最近尝试了一番,这个需求难以实现,而且其实是个伪需求。 对于你举的例子:
adapter.register(PostWrapper::class.java)
.withDataMapper { wrapper -> wrapper.post }
.to(PostViewBinder())
如果要做到类型安全,那么到 .to(PostViewBinder())
前,输入的类型必须确定。而实际情况是,.withDataMapper { wrapper -> wrapper.post }
要获得入参,得推迟到 link 阶段,因为这里的 wrapper
是鲜活的实例。这就导致了我们无法在注册阶段构建出新的 OneToManyBuilder<Post>
,因此出现矛盾。
另外,实际上 MultiType 原本就支持你所说的「不必把数据都写为 List<Any>
」,对于 sealed class
也是支持的,示例如下:
class SealedActivity : MenuBaseActivity() {
val items = ArrayList<ItemType>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_list)
val recyclerView = findViewById<RecyclerView>(R.id.list)
val adapter = MultiTypeAdapter(items)
adapter.register(Post::class, PostViewBinder())
items.add(Post("This is a sub class of sealed ItemType"))
recyclerView.adapter = adapter
}
}
sealed class ItemType
data class Banners(val size: Int) : ItemType()
data class Post(val title: String) : ItemType()
class PostViewBinder : ItemViewBinder<Post, PostViewBinder.ViewHolder>() {
override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): ViewHolder {
return ViewHolder(inflater.inflate(R.layout.item_post, parent, false))
}
override fun onBindViewHolder(holder: ViewHolder, item: Post) {
holder.setData(item)
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val title: TextView = itemView.findViewById(R.id.title)
fun setData(post: Post) {
title.text = post.title
}
}
}
可以见到,我们完全可以声明 val items = ArrayList<ItemType>()
而投入其子类实例,这符合你说的「不必把数据都写为 List<Any>
」。
实际上,MultiType 不止于此,如果我们能够继承上面的 Post,那么我们甚至可以往 items 中投入 Post 的子类实例,并且只要注册 adapter.register(Post::class, PostViewBinder())
即可,不必再注册这个 Post 的子类,因为 MultiType 如果找不到注册的类型,会默认通过 isAssignableFrom
去寻找实例的父类及其 binder。这么设计的好处是,一切都是类型安全的,如果你需要对于这个 Post 的子类提供更具体的 binder,应该去显式注册它。
因此,如果没有更多讨论,这个 issue 将在近期关闭。
我上面设想的主要是下面这种场景
sealed class ItemType1 {
data class Banners(val banners: List<RealBannerType>): ItemType1()
data class Post(val post: RealPostType): ItemType1()
}
sealed class ItemType2 {
data class Ad(val Ad: RealAdType): ItemType2()
data class Post(val post: RealPostType): ItemType2()
}
class PostViewBinder : ItemViewBinder<RealPostType, PostViewBinder.ViewHolder>() {
......
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
}
像这样如果多个地方有各自的 ItemType
,各自有一个 RealPostType
的 wrapper
Post
,如果 post
的展示是完全一样的,那么如果 binder
部分能够写为 ItemViewBinder<RealPostType, ...>
的话就可以在各个地方使用。
根据我多年使用 MultiType 的经历看来,我自己没有这方面的需求,而且这个 issue 长年来也没有其他人请求支持,因此将关闭。
按照现有的使用方式,在注册
ViewBinder
的时候,ViewBinder
内的数据类型必须和调用register
方法时参数类型一致。 这里希望可以添加一种方法,使得在注册的时候可以对数据类型进行映射,实现以下功能。这样如果我有多种数据类型在展示的话,就可以使用
sealed class
将多种类型包起来,这样各个页面就不必把数据都写为
List<Any>
了,然后ViewBinder
部分还是可以在多个页面间共用。