ListView与RecyclerView区别总结

1. 概述

在 Android 开发中,ListViewRecyclerView 是展示列表数据的核心控件。本文将从 代码实现性能优化功能扩展 等角度,全面对比两者的差异,并提供详细的实现步骤和最佳实践。


2. ViewHolder 模式实现对比

2.1 ListView 的 Adapter 实现(需手动优化)

java 复制代码
public class ListViewAdapter extends BaseAdapter {
    private List<String> mData;
    private LayoutInflater mInflater;

    public ListViewAdapter(Context context, List<String> data) {
        mData = data;
        mInflater = LayoutInflater.from(context);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // 手动实现 ViewHolder 模式
        ViewHolder holder;
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.item_list, parent, false);
            holder = new ViewHolder();
            holder.textView = convertView.findViewById(R.id.tv_item);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.textView.setText(mData.get(position));
        return convertView;
    }

    static class ViewHolder {
        TextView textView;
    }
}

2.2 RecyclerView 的 Adapter 实现(强制使用 ViewHolder)

java 复制代码
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {
    private List<String> mData;

    public RecyclerAdapter(List<String> data) {
        mData = data;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_recycler, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.textView.setText(mData.get(position));
    }

    static class MyViewHolder extends RecyclerView.ViewHolder {
        TextView textView;

        public MyViewHolder(View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.tv_item);
        }
    }
}

关键点总结

  • RecyclerView 强制封装 ViewHolder,避免开发者遗漏复用逻辑。
  • ListView 需要手动优化,若未正确复用 convertView 会导致性能问题。

3. 布局管理:灵活 vs 局限

3.1 RecyclerView 的多布局实现

java 复制代码
// 设置线性布局(垂直)
recyclerView.setLayoutManager(new LinearLayoutManager(context));

// 设置网格布局(3列)
recyclerView.setLayoutManager(new GridLayoutManager(context, 3));

// 设置瀑布流布局(3列,垂直方向)
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL));

3.2 ListView 的局限性

  • 原生仅支持垂直滚动,若需网格布局需自定义 Adapter,但复用逻辑复杂且性能差。

4. 数据更新机制对比

4.1 ListView 的全局刷新

java 复制代码
// 数据变更后必须全量刷新
mData.add("New Item");
adapter.notifyDataSetChanged(); // 性能低下!

4.2 RecyclerView 的局部更新

java 复制代码
// 插入单条数据
mData.add(position, "New Item");
adapter.notifyItemInserted(position); // 仅更新单个项

// 使用 DiffUtil 高效刷新(推荐!)
DiffUtil.DiffResult result = DiffUtil.calculateDiff(new MyDiffCallback(oldList, newList));
result.dispatchUpdatesTo(adapter);

DiffUtil 实现示例

java 复制代码
public class MyDiffCallback extends DiffUtil.Callback {
    private List<String> oldList, newList;

    public MyDiffCallback(List<String> oldList, List<String> newList) {
        this.oldList = oldList;
        this.newList = newList;
    }

    @Override
    public int getOldListSize() { return oldList.size(); }

    @Override
    public int getNewListSize() { return newList.size(); }

    @Override
    public boolean areItemsTheSame(int oldPos, int newPos) {
        return oldList.get(oldPos).equals(newList.get(newPos));
    }

    @Override
    public boolean areContentsTheSame(int oldPos, int newPos) {
        return oldList.get(oldPos).equals(newList.get(newPos));
    }
}

5. 动画与交互实现

5.1 RecyclerView 的内置动画

java 复制代码
// 默认动画(删除、插入、移动)
recyclerView.setItemAnimator(new DefaultItemAnimator());

// 自定义动画(示例:缩放动画)
public class ScaleItemAnimator extends DefaultItemAnimator {
    @Override
    public boolean animateAdd(RecyclerView.ViewHolder holder) {
        holder.itemView.setScaleX(0);
        holder.itemView.setScaleY(0);
        ObjectAnimator.ofPropertyValuesHolder(holder.itemView,
                PropertyValuesHolder.ofFloat(View.SCALE_X, 1),
                PropertyValuesHolder.ofFloat(View.SCALE_Y, 1))
                .setDuration(300)
                .start();
        return super.animateAdd(holder);
    }
}

5.2 ListView 的动画缺失

  • 需手动添加动画(如使用 ObjectAnimator 实现),代码复杂且兼容性差。

6. 分隔线与点击事件

6.1 RecyclerView 的分隔线自定义

java 复制代码
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
    private Paint mPaint;
    private int mDividerHeight;

    public DividerItemDecoration(Context context) {
        mPaint = new Paint();
        mPaint.setColor(Color.GRAY);
        mDividerHeight = context.getResources().getDimensionPixelSize(R.dimen.divider_height);
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        for (int i = 0; i < parent.getChildCount(); i++) {
            View child = parent.getChildAt(i);
            int top = child.getBottom() + ((RecyclerView.LayoutParams) child.getLayoutParams()).bottomMargin;
            c.drawRect(child.getLeft(), top, child.getRight(), top + mDividerHeight, mPaint);
        }
    }
}

6.2 点击事件处理对比

  • ListView :直接设置 OnItemClickListener
  • RecyclerView :需在 ViewHolder 中绑定
java 复制代码
public class MyViewHolder extends RecyclerView.ViewHolder {
    public MyViewHolder(View itemView) {
        super(itemView);
        itemView.setOnClickListener(v -> {
            if (listener != null) {
                listener.onItemClick(getAdapterPosition());
            }
        });
    }
}

7. 使用步骤总结

7.1 RecyclerView 使用流程

  1. 添加依赖implementation 'androidx.recyclerview:recyclerview:1.3.2'

  2. 布局文件

    xml 复制代码
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
  3. 设置 LayoutManager

    java 复制代码
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
  4. 实现 Adapter 和 ViewHolder(参考第2节)

  5. 绑定数据

    java 复制代码
    RecyclerAdapter adapter = new RecyclerAdapter(dataList);
    recyclerView.setAdapter(adapter);

7.2 ListView 使用流程

  1. 布局文件

    xml 复制代码
    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
  2. 实现 Adapter(参考第2节)

  3. 绑定数据

    java 复制代码
    listView.setAdapter(adapter);

8. 关键点总结

特性 ListView RecyclerView
复用机制 需手动优化,易出错 强制 ViewHolder,内置高效复用池
布局扩展性 仅支持垂直列表 支持线性/网格/瀑布流,灵活组合
数据刷新性能 全局刷新,性能差 局部刷新 + DiffUtil,高效更新
动画支持 需自定义实现 内置动画 API,支持深度定制
开发复杂度 简单场景快速实现 初期学习成本略高,长期维护更便捷

9. 结论与选型建议

  • 优先选择 RecyclerView:适用于所有新项目,尤其在需要复杂布局、动画或高性能的场景。
  • 仅考虑 ListView:仅用于维护旧项目或极其简单的静态列表,但建议逐步迁移至 RecyclerView。

源码级优化建议

  • 使用 RecyclerView 时,通过 setHasFixedSize(true) 提升性能(当 Item 尺寸固定时)。
  • 避免在 onBindViewHolder 中执行耗时操作(如加载图片),应使用异步加载库(如 Glide)。

通过本文的详细对比和代码实践,读者可全面掌握两者的差异与应用场景。建议收藏本文代码片段,作为日常开发的参考模板。

相关推荐
幻雨様2 小时前
UE5多人MOBA+GAS 45、制作冲刺技能
android·ue5
Jerry说前后端3 小时前
Android 数据可视化开发:从技术选型到性能优化
android·信息可视化·性能优化
Meteors.4 小时前
Android约束布局(ConstraintLayout)常用属性
android
alexhilton5 小时前
玩转Shader之学会如何变形画布
android·kotlin·android jetpack
whysqwhw9 小时前
安卓图片性能优化技巧
android
风往哪边走9 小时前
自定义底部筛选弹框
android
Yyyy48210 小时前
MyCAT基础概念
android
Android轮子哥10 小时前
尝试解决 Android 适配最后一公里
android
雨白11 小时前
OkHttp 源码解析:enqueue 非同步流程与 Dispatcher 调度
android
风往哪边走12 小时前
自定义仿日历组件弹框
android