Android recycler view 一次通关

前言

Android的RecyclerView是一个非常强大且灵活的组件,用于在Android应用中显示动态或静态数据列表。它是ListViewGridView的现代替代品,提供了更好的性能和更多的定制选项。

ViewHolder

ViewHolder用于保存视图引用,每个视图项在滚动时都会被重用。

public class MyViewHolder extends RecyclerView.ViewHolder {
    public TextView textView;
    public MyViewHolder(View itemView) {
        super(itemView);
        textView = itemView.findViewById(R.id.textview);
    }
}

为什么要存在ViewHolder

ViewHolder 的主要目的是提高列表滚动的性能和流畅性。在传统的 ListView 中,每次滚动到新的列表项时,都会调用 findViewById() 来获取视图对象,这个过程是相当耗时的,特别是在处理大量数据时,因为 findViewById() 需要在视图层级中逐一查找,这对性能有较大影响。 

  • 视图缓存ViewHolder 提供了一种方式来缓存视图引用,即每个列表项的视图在初次创建时就缓存下来,之后可以直接重用视图引用而无需重新查找,大幅减少了 findViewById() 的调用次数。
  • 快速绑定数据:因为视图已经被缓存,所以可以快速地将数据绑定到这些视图上,而不是每次都重新创建视图。

Adapter

Adapter负责将数据绑定到ViewHolder的视图上。

public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
    private String[] mDataset;

    public MyAdapter(String[] myDataset) {
        mDataset = myDataset;
    }

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

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.textView.setText(mDataset[position]);
    }

    @Override
    public int getItemCount() {
        return mDataset.length;
    }
}

AdapterRecyclerView 设计中扮演着桥梁的角色,它将底层数据与 RecyclerView 显示的视图连接起来。

  1. Adapter 管理所有需要显示在 RecyclerView 中的数据。它将这些数据转换成视图,让用户可以在屏幕上看到。这种模式让视图显示逻辑和数据处理逻辑分离,更容易维护和扩展。
  2. Adapter 负责根据数据创建相应的 ViewHolder。这包括决定使用哪种类型的视图(列表、网格或自定义视图)并将数据绑定到这些视图上。
  3. 当底层数据发生变化时,Adapter 提供了一套方法(如 notifyDataSetChanged(), notifyItemInserted() 等)来通知 RecyclerView 需要重新绘制界面。这使得数据的变更可以高效且动态地反映在用户界面上。
  4. 通过使用 AdapterViewHolder 的组合,RecyclerView 可以有效地重用已经不在屏幕上的视图。这种重用机制减少了内存的使用和垃圾回收的频率,从而提升了应用的性能。 

布局管理器

  • LinearLayoutManager:显示垂直或水平滚动的列表。
  • GridLayoutManager:显示二维滚动网格。
  • StaggeredGridLayoutManager:显示交错网格,用于瀑布流布局。

动态数据更新

1. 数据更新 利用Adapter的notifyItemInserted(), notifyItemRemoved(), 和 notifyItemChanged()方法来通知数据变更。

2. 效率优化 使用DiffUtil类来计算数据差异,并提供更平滑的动画效果。

DiffUtil 使用一种差异算法来比较两个列表的内容差异。这个算法能够找出最小数量的修改步骤来将一个列表转换成另一个列表,这些步骤包括:

  • 插入
  • 移除
  • 替换

创建 DiffUtil.Callback 这个回调类需要实现几个方法来判断两个列表项是否是同一项,以及同一项的内容是否发生了变化。

DiffUtil.Callback diffCallback = new DiffUtil.Callback() {
    @Override
    public int getOldListSize() {
        return oldList.size();
    }

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

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        return oldList.get(oldItemPosition).getId().equals(newList.get(newItemPosition).getId());
    }

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

计算差异 使用 DiffUtil.calculateDiff() 方法计算差异。这个过程是同步进行的,因此建议在后台线程中执行,以避免阻塞主线程。

DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);

应用差异结果 在主线程中,使用 dispatchUpdatesTo() 方法将差异结果应用到适配器上,这会触发 RecyclerView 的局部更新。

diffResult.dispatchUpdatesTo(adapter);

它只更新变更的部分,而不是重新渲染整个列表。

Recycler View的缓存机制

RecyclerView 的缓存机制是设计来优化滚动性能的核心部分,通过复用和有效管理视图对象来减少创建和销毁视图的开销,RecyclerView 提供了四个不同层次的缓存,以确保滚动时的高效率和流畅性。

mAttachedScrap:缓存屏幕中可见范围的ViewHolder

mAttachedScrap 集合存储了当前屏幕上可见的ViewHolder。这些ViewHolder 实际上已经被绑定到了其对应的数据,并且处于活跃状态,也就是说它们目前仍然附加在RecyclerView上。

当进行数据更新(如调用notifyDataSetChanged())时,RecyclerView 可以快速访问这些ViewHolder,进行必要的更新而无需重新创建或进行复杂的查找操作。

mCachedViews:缓存滑动时即将与RecyclerView分离的ViewHolder

mCachedViews 缓存了那些已经滑出屏幕,但是可能很快会再次滑入屏幕的ViewHolder。这个缓存通常包含少量的ViewHolder,默认情况下是最多2个。

这种缓存策略可以显著提高滚动的流畅性,尤其是在用户进行快速滑动时,减少了创建和绑定ViewHolder的开销。

ViewCacheExtension:自定义实现的缓存

ViewCacheExtension 是一个可选的扩展,允许开发者根据自己的特定需求来实现自定义的缓存策略。

通过继承ViewCacheExtension 并实现其getViewForPositionAndType() 方法,开发者可以控制如何缓存视图。这对于处理那些有特殊缓存需求或是不常规大小的ViewHolder特别有用。

RecycledViewPool:ViewHolder缓存池

RecycledViewPool 允许ViewHolder 跨多个RecyclerView实例共享。它主要用于存储那些已经完全从RecyclerView 中分离出来的ViewHolder

此缓存池特别适合于应用中有多个RecyclerView需要显示相似数据的情况。通过共享ViewHolder,可以显著减少内存的使用和提高性能。

  • 30
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
下面是一个简单的RecyclerView实例,其中包含一个列表视图,该视图显示一些文本项。 MainActivity.java ``` public class MainActivity extends AppCompatActivity { private RecyclerView mRecyclerView; private RecyclerView.Adapter mAdapter; private RecyclerView.LayoutManager mLayoutManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view); mRecyclerView.setHasFixedSize(true); mLayoutManager = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(mLayoutManager); String[] myDataset = {"Item 1", "Item 2", "Item 3"}; mAdapter = new MyAdapter(myDataset); mRecyclerView.setAdapter(mAdapter); } } ``` MyAdapter.java ``` public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private String[] mDataset; public static class ViewHolder extends RecyclerView.ViewHolder { public TextView mTextView; public ViewHolder(View v) { super(v); mTextView = (TextView) v.findViewById(R.id.text_view); } } public MyAdapter(String[] myDataset) { mDataset = myDataset; } @Override public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.list_item, parent, false); ViewHolder vh = new ViewHolder(v); return vh; } @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.mTextView.setText(mDataset[position]); } @Override public int getItemCount() { return mDataset.length; } } ``` activity_main.xml ``` <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` list_item.xml ``` <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" android:textAppearance="?android:attr/textAppearanceListItem" /> ``` 这个RecyclerView实例使用了一个LinearLayoutManager和一个MyAdapter。MyAdapter通过ViewHolder来管理每个列表项的视图。在onCreateViewHolder()方法中,我们使用LayoutInflater将list_item.xml布局文件转换为一个View对象,然后将其传递给ViewHolder。在onBindViewHolder()方法中,我们将mDataset中对应位置的文本设置为ViewHolder中的mTextView中的文本。最后,在MainActivity的onCreate()方法中,我们创建一个LayoutManager和一个Adapter,并将Adapter设置为RecyclerView的适配器。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏目艾拉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值