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

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

相关推荐
雨白12 小时前
Android 快捷方式实战指南:静态、动态与固定快捷方式详解
android
hqk12 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
LING13 小时前
RN容器启动优化实践
android·react native
恋猫de小郭15 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker21 小时前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴21 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭1 天前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab1 天前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe2 天前
Now in Android 架构模式全面分析
android·android jetpack
二流小码农2 天前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos