推荐一个极简通用的RecyclerView Adapter库——NoAdapter

10 篇文章 0 订阅

你是否还在为项目中众多的列表样式而发愁?你是否还在为一遍遍机械重复的编写Adapter代码而厌倦?你是否还在为编写多类型卡片列表的众多细节而一次次的百度?是时候找一个更高效的手段来解脱自己了。NoAdapter——一个为解决Android列表开发的组件库。

正如这个库的名称一样,NoAdapter致力于打造一个极简的RecycleView的Adapter组件,可以让开发者更专注于业务本身的卡片(item)开发,忽略复杂、繁琐、重复(尤其是一个列表有多种卡片类型的情况)的Adapter代码的开发,不用开发一行Adapter代码,真正的做到 No Adapter。

它的优点如下:

  1. 极简,只需一行注解即完成开发,具体见下面的使用方法介绍;
  2. 对数据结构无依赖;
  3. 使用之后可以彻底干掉项目里的XXXAdapter类了。

一、如何使用

1.添加依赖和配置

在project的根build.gradle里添加maven仓储
maven { url 'https://jitpack.io' }

module下的build.gradle里添加配置和依赖

android {
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [ moduleName : 'xxxx' ]
            }
        }
    }
}

dependencies{
	implementation 'com.github.chenchongyu:NoAdapter-Library:vx.x.x'
	annotationProcessor 'com.github.chenchongyu:NoAdapter-Compiler:vx.x.x'
}

同时,添加如下混淆配置:

-keep public class com.runningcode.noadapter.** { *; }
-keep public class * extends com.runningcode.noadapter.adpater.BaseVH
-keepattributes *Annotation*

2.编写ViewHolder

添加@ViewHolder注解,继承BaseVH类,泛型里指定当前ViewHolder需要的数据类型

@ViewHolder
public class UserHolder extends BaseVH<User> {
    private ImageView imageView;

    public UserHolder(ViewGroup parent) {
        super(parent, R.layout.item_image);
        imageView = itemView.findViewById(R.id.image);
    }

    @Override
    public void bindData(User data) {
        imageView.setImageResource(data.image);
    }
}

3.使用

首先要在应用初始化的时候注册一下(建议在application里)

ViewHolderRegistry.add(new ViewHolderRegistry_xxx());
ViewHolderRegistry.add(new ViewHolderRegistry_xxxxb());

其中ViewHolderRegistry_后面的字符就是你在gradle里配置的moduleName。
当然,这一步也可以省略调,你只需要在project和module的build.gradle里添加如下配置即可:
classpath 'com.github.chenchongyu:NoAdapter-Plugin:v1.0.0.1'
apply plugin: 'no-adapter-plugin'

List allList = new ArrayList();

allList.add(new User());

NoAdapter adapter = new NoAdapter(allList);

mRecyclerView.setAdapter(adapter);

如上,一个列表页就开发完了,是不是很简单?

二、高阶用法

1.添加ItemClick事件

NoAdapter adapter = newNoAdapter(allList);

adapter.setListener(newOnItemClickListener() {

    @Override
    
    publicvoidonItemClick(Object data) {
    
    }
    
});

2.如果列表的多类型卡片不是通过数据类型来区分的,而是通过同一个数据类型里的不同字段来区分的?那怎么办?

比如,一个聊天消息列表,根据类型的不同显示文字消息、语音消息、图片消息等,返回的数据结构如下:

Class ChatMsg{
    publicString msg;
    publicinttype; // 0:文字;1:语音;2:图片
}

在以前的开发过程中,开发者可以自己根据业务在adapter的getItemType()里返回对应卡片的类型,然后根据类型不同来创建不同的卡片。
现在我们已经没有Adapter了,那我们要怎么处理呢 ?
直接上代码:

@ViewHolder(cls = ChatMsg.class, filed = "type", type = 0)
public class TextMsgViewHolder extends BaseVH<ChatMsg> {
    private TextView textView;
    private ImageView imageView;
 
    public News1ViewHolder(@NonNull ViewGroup parent) {
        super(parent, R.layout.item_msg_text);
        textView = itemView.findViewById(R.id.text);
        imageView = itemView.findViewById(R.id.image);
    }
 
    @Override
    public void bindData(ChatMsg data) {
        textView.setText(data.title);
        Glide.with(itemView.getContext()).load(data.url).into(imageView);
    }
 
}
 
 
@ViewHolder(cls = ChatMsg.class, filed = "type", type = 1)
public class AudioMsgViewHolder extends BaseVH<ChatMsg> {
    private TextView textView;
    private ImageView imageView;
 
    public News1ViewHolder(@NonNull ViewGroup parent) {
        super(parent, R.layout.item_msg_audio);
        textView = itemView.findViewById(R.id.text);
        imageView = itemView.findViewById(R.id.image);
    }
 
    @Override
    public void bindData(ChatMsg data) {
        textView.setText(data.title);
        Glide.with(itemView.getContext()).load(data.url).into(imageView);
    }
 
}

可以看到,还是在viewholder里添加如下注解

@ViewHolder(cls = ChatMsg.class, filed = "type", type = 1)

只是在注解里标明对应的数据类型、字段名和字段值即可。

完整demo工程请移步:NoAdapter-Example

三、基本原理

基本原理就是通过APT和反射,我们可以通过@ViewHolder注解收集到所有的ViewHolder以及其对应的泛型,把它注册到我们自己的注册中心,然后再使用NoAdapter的时候,通过注册中心类获取ItemType、ViewHolder类即可。

通过实现一个Adapter我们知道,其基本操作就是继承 RecyclerView.Adapter
,同时重写onCreateViewHolder、onBindViewHolder和getItemCount等方法,如果你的列表有多重类型的item,那么还要再重写getItemViewType方法,通过观察我们可以发现,getItemViewType返回的是一个代表item类型的int值,然后onCreateViewHolder通过这个类型来创建ViewHolder,然后在onBindViewHolder里向ViewHolder
bind数据。这里边最关键的有两点——如何确定itemType,以及如何通过itemType来确定ViewHolder?

通常我们给Adapter传递的数据集合里都是List这种类型,那么其实这个集合里有几种类型(对应的class)是可以确定的,我们只需要把class转成getItemViewType需要的int类型就可以了,这点通过Object的hashCode方法就可以做到。
确定了itemType之后,如何通过ItemType来确定ViewHolder呢?其实在我们开发的时候,每个ViewHolder是知道自己要处理何种数据(Class)的,那么我们就可以通过一个注册中心,把所有的ClassType和ViewHolder一一对应起来,这样我们就可以通过ItemType来找到ViewHolder了。

@ViewHolder
public class UserHolder extends BaseVH<User>{}

通过如上的声明,我们可以在编译期就找到所有的ViewHolder类以及其需求的Object类,这样就可以填充我们的注册中心了。
有了注册中心之后,Adapter就完全可以自动化了,关键代码如下:

// 通过注册中心查找itemType
 public int getItemViewType(int position) {
        return ViewHolderRegistry.getItemViewType(dataList.get(position));
    }
    
  // 通过ItemType查找ViewHolder
public BaseVH<?> onCreateViewHolder(ViewGroup parent, int viewType) {
	Class<?> vhClass = ViewHolderRegistry.getVHClass(viewType);
	Constructor<?> constructor = vhClass.getConstructor(ViewGroup.class);
      BaseVH<?> viewHolder = (BaseVH<?>) constructor.newInstance(parent);
      	return viewHolder;
}

 // 给ViewHolder 设置数据
 public void onBindViewHolder(BaseVH holder, int position) {
        final Object data = dataList.get(position);

        holder.bindData(data); 
    }

更多信息请查看 NoAdapter-Library

讨论

QQ讨论群:984012228

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值