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)。

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

相关推荐
doublelixin2 小时前
AOSP (Android11) 集成Google GMS三件套
android
xzkyd outpaper5 小时前
onSaveInstanceState() 和 ViewModel 在数据保存能力差异
android·计算机八股
梓仁沐白6 小时前
【Kotlin】协程
开发语言·python·kotlin
CYRUS STUDIO6 小时前
FART 脱壳某大厂 App + CodeItem 修复 dex + 反编译还原源码
android·安全·逆向·app加固·fart·脱壳
WAsbry6 小时前
现代 Android 开发自定义主题实战指南
android·kotlin·material design
xzkyd outpaper7 小时前
Android动态广播注册收发原理
android·计算机八股
唐墨1237 小时前
android与Qt类比
android·开发语言·qt
林林要一直努力8 小时前
Android Studio 向模拟器手机添加照片、视频、音乐
android·智能手机·android studio
AD钙奶-lalala8 小时前
Mac版本Android Studio配置LeetCode插件
android·ide·android studio
梓仁沐白9 小时前
【Kotlin】注解&反射&扩展
开发语言·python·kotlin