如何在同一RecyclerView Adapter中适配不同类型的ArrayList?
解决同一RecyclerView Adapter适配多种ArrayList的问题
嘿,这个场景太常见了!我之前帮好几个开发者解决过类似的问题——同一个Adapter要给多个页面的RecyclerView用,还得适配不同类型的数据源,核心就是让getItemCount()能动态返回当前数据源的长度,同时保证数据绑定的灵活性。下面给你两个实用的方案,你可以根据自己的代码风格选:
方案一:泛型+数据绑定回调(推荐,扩展性强)
这个方案通过泛型让Adapter支持任意数据类型,再用一个回调接口让每个页面自己处理数据到View的绑定逻辑,完美适配你的需求。
第一步:编写泛型Adapter
public class CommonRecyclerAdapter<T> extends RecyclerView.Adapter<CommonRecyclerAdapter.CommonViewHolder> { private List<T> mDataSource; private LayoutInflater mInflater; private OnBindDataListener<T> mBindListener; // 定义数据绑定的回调接口,让外部实现具体的绑定逻辑 public interface OnBindDataListener<T> { void onBindData(T item, CommonViewHolder holder); } // 构造方法:传入上下文、数据源、绑定回调 public CommonRecyclerAdapter(Context context, List<T> dataSource, OnBindDataListener<T> bindListener) { mInflater = LayoutInflater.from(context); mDataSource = dataSource; mBindListener = bindListener; } // 更新数据源的方法,调用后会刷新列表 public void updateDataSource(List<T> newData) { if (mDataSource != null) { mDataSource.clear(); mDataSource.addAll(newData); } else { mDataSource = newData; } notifyDataSetChanged(); } @NonNull @Override public CommonViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { // 加载你的通用item布局 View itemView = mInflater.inflate(R.layout.your_common_item_layout, parent, false); return new CommonViewHolder(itemView); } @Override public void onBindViewHolder(@NonNull CommonViewHolder holder, int position) { // 拿到当前位置的数据,交给外部回调处理绑定 T item = mDataSource.get(position); mBindListener.onBindData(item, holder); } @Override public int getItemCount() { // 直接返回当前数据源的长度,空的话返回0避免空指针 return mDataSource != null ? mDataSource.size() : 0; } // 通用ViewHolder,这里定义你item布局里的所有View public static class CommonViewHolder extends RecyclerView.ViewHolder { public TextView tvContent; public ImageView ivIcon; // 可以根据你的布局添加更多View public CommonViewHolder(@NonNull View itemView) { super(itemView); tvContent = itemView.findViewById(R.id.tv_content); ivIcon = itemView.findViewById(R.id.iv_icon); } } }
第二步:在各个Activity中使用
比如第一个Activity用User类型的列表:
// 初始化你的用户数据列表 List<User> userList = new ArrayList<>(); // 填充数据... // 创建Adapter,传入User类型和对应的绑定逻辑 CommonRecyclerAdapter<User> userAdapter = new CommonRecyclerAdapter<>(this, userList, (item, holder) -> { holder.tvContent.setText(item.getUserName()); holder.ivIcon.setImageResource(item.getAvatarResId()); }); // 设置给RecyclerView recyclerView.setAdapter(userAdapter);
第二个Activity用Product类型的列表:
List<Product> productList = new ArrayList<>(); // 填充数据... CommonRecyclerAdapter<Product> productAdapter = new CommonRecyclerAdapter<>(this, productList, (item, holder) -> { holder.tvContent.setText(item.getProductName()); holder.ivIcon.setImageResource(item.getProductImageResId()); }); recyclerView.setAdapter(productAdapter);
这样getItemCount()会自动根据当前泛型列表的长度返回正确值,而且每个页面可以自定义数据绑定逻辑,完全不冲突。
方案二:多数据源+类型标记(适合不想用泛型的场景)
如果你的项目里泛型用得不多,也可以给Adapter维护多个数据源,用一个标记变量区分当前使用的类型,在getItemCount()和数据绑定的时候做判断。
编写Adapter
public class CommonRecyclerAdapter extends RecyclerView.Adapter<CommonRecyclerAdapter.CommonViewHolder> { private List<User> mUserList; private List<Product> mProductList; private List<Order> mOrderList; private int mCurrentType; private LayoutInflater mInflater; // 定义类型常量 public static final int TYPE_USER = 0; public static final int TYPE_PRODUCT = 1; public static final int TYPE_ORDER = 2; public CommonRecyclerAdapter(Context context, int currentType) { mInflater = LayoutInflater.from(context); mCurrentType = currentType; } // 分别设置不同类型的数据源 public void setUserList(List<User> userList) { mUserList = userList; notifyDataSetChanged(); } public void setProductList(List<Product> productList) { mProductList = productList; notifyDataSetChanged(); } public void setOrderList(List<Order> orderList) { mOrderList = orderList; notifyDataSetChanged(); } @Override public int getItemCount() { // 根据当前类型返回对应列表的长度 switch (mCurrentType) { case TYPE_USER: return mUserList != null ? mUserList.size() : 0; case TYPE_PRODUCT: return mProductList != null ? mProductList.size() : 0; case TYPE_ORDER: return mOrderList != null ? mOrderList.size() : 0; default: return 0; } } @Override public void onBindViewHolder(@NonNull CommonViewHolder holder, int position) { // 根据类型绑定对应的数据 switch (mCurrentType) { case TYPE_USER: User user = mUserList.get(position); holder.tvContent.setText(user.getUserName()); holder.ivIcon.setImageResource(user.getAvatarResId()); break; case TYPE_PRODUCT: Product product = mProductList.get(position); holder.tvContent.setText(product.getProductName()); holder.ivIcon.setImageResource(product.getProductImageResId()); break; case TYPE_ORDER: Order order = mOrderList.get(position); holder.tvContent.setText(order.getOrderNumber()); break; } } // ViewHolder和onCreateViewHolder和方案一一致 public static class CommonViewHolder extends RecyclerView.ViewHolder { public TextView tvContent; public ImageView ivIcon; public CommonViewHolder(@NonNull View itemView) { super(itemView); tvContent = itemView.findViewById(R.id.tv_content); ivIcon = itemView.findViewById(R.id.iv_icon); } } }
在Activity中使用
// 用户列表页面 CommonRecyclerAdapter adapter = new CommonRecyclerAdapter(this, CommonRecyclerAdapter.TYPE_USER); adapter.setUserList(userList); recyclerView.setAdapter(adapter);
这个方案的缺点是以后如果要新增数据类型,就得修改Adapter的代码,扩展性不如方案一,所以更推荐第一种泛型的方式。
额外注意事项
- 如果你的数据量很大,建议用
DiffUtil来优化数据源更新,避免全量刷新RecyclerView,提升性能。 - 确保在主线程调用
notifyDataSetChanged()或者updateDataSource()方法,避免UI线程异常。 - ViewHolder里的View一定要正确初始化,避免空指针异常。
内容的提问来源于stack exchange,提问作者developer
相关产品推荐
相关产品推荐

