知乎 App 中存在大量的列表页面,可预见的未来还会不断增加,因此需要一种易上手、可维护的列表「脚手架」来支撑业务需求。
假定读者对 RecyclerView 的 原始写法 相对熟悉。一些简化 RecyclerView 使用难度的方案试图通过绕过 ViewHolder 的概念,进而直接操纵 ViewHolder 其中的 View ,代码相对中心化,失去了 ViewHolder 的可复用性;另一些也没能简化编写 Adapter 的冗余代码,仅仅把 Adapter 的概念带到了其他地方。SugarAdapter 不会试图逃避任何 RecyclerView 的所有概念,仅仅是写法上的简化,没有额外的认知成本(详细介绍可参见 GitHub 链接 )。
首先,你不需要继承并复写 Adapter ,即使是复杂类型的列表,也只需要写几行 Builder 模式的代码,冗余代码全部通过 annotationProcessor 生成:
mAdapter = SugarAdapter.Builder.with(mList) // eg. List<Object>
.add(FooHolder.class) // extends SugarHolder<Foo>
.add(BarHolder.class, new SugarHolder.OnCreatedCallback<BarHolder>() {
@Override
public void onCreated(@NonNull BarHolder holder) {
// holder.SETTER etc.
}
})
.build();
mRecyclerView.setAdapter(mAdapter);
// mAdapter.notifyItem* or mAdapter.notifyDataSetChanged()
// mAdapter.setExtraDelegate() with onAttachedToRecyclerView()/onDetachedFromRecyclerView()
复制代码
接着是 SugarHolder 。在长时间使用 RecyclerView 创建多种列表视图的过程中,我们注意到,通常对于一个 ViewHolder 而言,其 ViewType(类型)、Layout(视图层)和 Data(数据)是强相关的,因此我们简单认为 Layout – ViewType – Data 是「三位一体」的存在,这一模式对于简化 RecyclerView 的使用十分有效。此外,ViewHolder 本身可以视为列表中细粒度的 Controller ,与编写一个简单的 Activity 或者 Fragment 没有明显区别:
// 务必注解的保证子类是 public 和 final 的;R.layout.foo 同时也是 ViewType
@Layout(R.layout.foo)
public final class FooHolder extends SugarHolder<Foo> {
// 如果你不想手写 findViewById() 代码,
// 只需要给定义的 View 加上 @Id() 注解,并且保证它为 public 的即可;
// @Id() 同样只能作用于 **final** class
@Id(R.id.text);
public TextView mTextView;
public FooHolder(@NonNull View view) {
super(view);
}
@Override
pubilc void onBindData(@NonNull Foo foo) {
mTextView.setText(foo.getText());
}
}
复制代码
经过上述过程,构造列表页面的过程基本完成了。在 annotationProcessor 的帮助下省去了需要人工编写的冗余代码,同时隐藏了中心化的列表绑定逻辑,使得 RecyclerView 的相关的代码更易于维护和上手。经过知乎 Android 一年多的线上实践表明,这种设计在客户端存在大量列表视图类型的情况下,其复杂度并没有提升,可以说是一套不错的解决方案(其实是我比较懒,一年多前写好了,现在才开源。
项目地址和详细解释:https://github.com/zhihu/SugarAdapter
(不要忘记点击右上角的 Star 🌟按钮哟
我想马上引入:
dependencies {
// 如果你想要迁移到 AndroidX ,可以使用 1.8.3
implementation 'com.zhihu.android:sugaradapter:1.7.5'
annotationProcessor 'com.zhihu.android:sugaradapter-processor:1.7.5'
}
复制代码
评论