(一)RecycleView 复用机制onCreateView和onBindView调用关系

推荐阅读 

(一)RecycleView 复用机制onCreateView和onBindView调用关系

(二)RecycleView实现吸附小标题的Demo(附源码)

(三)RecycleView 自定义下拉刷新,上拉加载监听

(四)RecycleView 滑动到置顶、Adapter局部刷新

(五)RecycleView 动态设置改变列表显示的高度

(六)RecycleView 回收复用机制简单总结

(七)RecycleView 性能提升、卡顿优化


目录

导语

一、上代码嘞!

二、布局文件

三、绑定数据

四、运行结果

五、Log日志分析

1、当第一屏页面显示出现数据时:

2、然后,我们滑动到底部,打印如下:  

3、最后,我们滑动到顶部,打印如下:  

六、Recycle 复用回收机制

(1)复用机制

(2)回收机制

结尾,送菊花。


    As we all know-众所周知,RecycleView 在展示数据列表的页面替换Listview的趋势已然出现,现在网络上关于它的资料也是铺天盖地,我就不再介绍如何使用了。但是,我对RecycleView的Adapter还是比较感兴趣的,因为懂得了Adapter,对于RecycleView的扩展及优化会很有帮助。这篇文章,先了解一下 onCreateViewHolder调用次数和 onBindViewHolder 之间的暧昧关系。

添加依赖

com.android.support:appcompat-v7:26.1.0
com.android.support:recyclerview-v7:26.1.0

(提示小技巧:根据自己android.support 版本去调整recycleView依赖版本)


一、上代码嘞!

RecyclerViewAdapter.class :继承RecyclerView.Adapter后,会重写三个方法:

public class RecycleViewAdapter extends RecyclerView.Adapter {

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return null;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

    }

    @Override
    public int getItemCount() {
        return 0;
    }
}

 onCreateViewHolder():负责承载每个子项的布局。它有两个参数,其中一个是“ int viewType”。

onBindViewHolder():负责将每个子项holder绑定数据。俩参数是“RecyclerView.ViewHolder holder”、“int position” 。

by the way,顺便说下,该类继承的RecyclerView.Adapter,其实可以加泛型ViewHolder,如下:

public class RecycleViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return null;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

    }

    @Override
    public int getItemCount() {
        return 0;
    }
}

二、布局文件

item_layout.xml 。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/txt"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:text="xxx"/>

</LinearLayout>
 

Usually-通常情况下,我们会define一个ViewHolder类喔,这样方便绑定数据和扩展。

 public Context mContext;
    static class ViewHolde extends RecyclerView.ViewHolder {

        TextView txt;
        public ViewHolde(View itemView) {
            super(itemView);
            txt = itemView.findViewById(R.id.txt);
        }
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View item = LayoutInflater.from(mContext).inflate(R.layout.item_layout , parent ,false);
        return new RecyclerAdapter.ViewHolde(item);
    }

三、绑定数据

data.class 实体类。(动手敲代码的复制即可)

public class data {
    /**
     * 名字
     */
    private String name;
    /**
     * 子项类型
     * 1: 标题
     * 2:普通
     */
    private int type;
    public data(String name, int type) {
        this.name = name;
        this.type = type;
    }
    public String getName() {
        return name;
    }
    
    public int getType() {
        return type;
    }
    /**
     * 存储的数据列表
     */
    private static List<data> mDataList;
    public static List<data> getDataList() {
        if (mDataList == null){
            mDataList = new ArrayList<>();

            data bean1 = new data("热销推荐",1);
            mDataList.add(bean1);
            mDataList.addAll(foods("热销零食"));

            data bean2 = new data("菜品",1);
            mDataList.add(bean2);
            mDataList.addAll(foods("小菜一碟"));

            data bean3 = new data("主食",1);
            mDataList.add(bean3);
            mDataList.addAll(foods("馒头,嗷~"));

            data bean4 = new data("饮料",1);
            mDataList.add(bean4);
            mDataList.addAll(foods("啤酒饮料矿泉水"));

        }
        return mDataList;
    }
    /**
     * 循环存储食物名字
     * @param foodName
     * @return
     */
    private static List<data> foods(String foodName){
        List<data> foods =new ArrayList<>();
        data food = null;
        for (int i = 0 ; i < 10 ; i++){
            food = new data(foodName+"("+i+")",2);
            foods.add(food);
        }
        return foods;
    }
}

索性,我就把Adapter里的全部代码贴出来咯!其实代码很简单,如下:

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    /**
     * context
     */
    public Context mContext;

    /**
     * 集合
     */
    public List<data> mDatas = new ArrayList<>();
    /**
     * data
     */
    public data mData;

    public RecyclerAdapter(Context mContext, List<data> mDatas) {
        this.mContext = mContext;
        this.mDatas = mDatas;
    }

    static class ViewHolde extends RecyclerView.ViewHolder {

        TextView txt;
        public ViewHolde(View itemView) {
            super(itemView);
            txt = itemView.findViewById(R.id.txt);
        }
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View item = LayoutInflater.from(mContext).inflate(R.layout.item_layout , parent ,false);
        Log.d("aaa","onCreateViewHolder————"+viewType);
        if (viewType == 1){//标题
            item.setTag(true);
        }else{
            item.setTag(false);
        }
        return new ViewHolde(item);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof  ViewHolde){
            mData =mDatas.get(position);
           ((ViewHolde) holder).txt.setText(mData.getName());
            Log.d("aaa","onBindViewHolder————"+mData.getName());
           if (mData.getType() == 1){
               ((ViewHolde) holder).txt .setTextColor(mContext.getColor(R.color.colorAccent));
               ((ViewHolde) holder).txt .setBackgroundColor(mContext.getColor(R.color.colorPrimary));
               ((ViewHolde) holder).txt .setTextSize(20);
           }
        }
    }

    @Override
    public int getItemViewType(int position) {
        Log.d("aaa","getItemViewType————"+ mDatas.get(position).getType());
        return mDatas.get(position).getType();
    }
   
    @Override
    public int getItemCount() {
        return mDatas.size();
    }
}

四、运行结果

public class MainActivity extends AppCompatActivity {

    RecyclerView mRecyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRecyclerView  =findViewById(R.id.recyclelist);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mRecyclerView.setAdapter(new RecyclerAdapter(this, data.getDataList()));
    }
}

好了,我们先运行看效果吧。

估计,看官们看代码也已经不耐烦了吧?  

看完效果,我们接着说。


五、Log日志分析

为了探究onCreateViewHolder和onBindViewHolder的调用次数,上面dapter代码贴出后,大家可能没注意,其实我在关键地方都标有log输出。

1、当第一屏页面显示出现数据时:

12-26 17:44:58.698 9860-9860/? D/aaa: onCreateViewHolder————1
12-26 17:44:58.699 9860-9860/? D/aaa: onBindViewHolder————热销推荐
12-26 17:44:58.705 9860-9860/? D/aaa: onCreateViewHolder————2
12-26 17:44:58.706 9860-9860/? D/aaa: onBindViewHolder————热销零食(0)
12-26 17:44:58.710 9860-9860/? D/aaa: onCreateViewHolder————2
12-26 17:44:58.710 9860-9860/? D/aaa: onBindViewHolder————热销零食(1)
12-26 17:44:58.715 9860-9860/? D/aaa: onCreateViewHolder————2
12-26 17:44:58.715 9860-9860/? D/aaa: onBindViewHolder————热销零食(2)
12-26 17:44:58.720 9860-9860/? D/aaa: onCreateViewHolder————2
12-26 17:44:58.720 9860-9860/? D/aaa: onBindViewHolder————热销零食(3)
12-26 17:44:58.725 9860-9860/? D/aaa: onCreateViewHolder————2
12-26 17:44:58.725 9860-9860/? D/aaa: onBindViewHolder————热销零食(4)
12-26 17:44:58.731 9860-9860/? D/aaa: onCreateViewHolder————2
12-26 17:44:58.731 9860-9860/? D/aaa: onBindViewHolder————热销零食(5)
12-26 17:44:58.736 9860-9860/? D/aaa: onCreateViewHolder————2
12-26 17:44:58.736 9860-9860/? D/aaa: onBindViewHolder————热销零食(6)
12-26 17:44:58.741 9860-9860/? D/aaa: onCreateViewHolder————2
12-26 17:44:58.741 9860-9860/? D/aaa: onBindViewHolder————热销零食(7)
12-26 17:44:58.746 9860-9860/? D/aaa: onCreateViewHolder————1
12-26 17:44:58.746 9860-9860/? D/aaa: onBindViewHolder————菜品
12-26 17:44:58.752 9860-9860/? D/aaa: onCreateViewHolder————2
12-26 17:44:58.752 9860-9860/? D/aaa: onBindViewHolder————小菜一碟(0)
12-26 17:44:58.757 9860-9860/? D/aaa: onCreateViewHolder————2
12-26 17:44:58.757 9860-9860/? D/aaa: onBindViewHolder————小菜一碟(1)
12-26 17:44:58.761 9860-9860/? D/aaa: onCreateViewHolder————2
12-26 17:44:58.761 9860-9860/? D/aaa: onBindViewHolder————小菜一碟(2)
12-26 17:44:58.765 9860-9860/? D/aaa: onCreateViewHolder————2
12-26 17:44:58.765 9860-9860/? D/aaa: onBindViewHolder————小菜一碟(3)
12-26 17:44:58.768 9860-9860/? D/aaa: onCreateViewHolder————2
12-26 17:44:58.768 9860-9860/? D/aaa: onBindViewHolder————小菜一碟(4)
12-26 17:44:58.807 9860-9860/? D/aaa: onCreateViewHolder————1
12-26 17:44:58.808 9860-9860/? D/aaa: onBindViewHolder————热销推荐

我第一眼看上去,以为onCreateViewHolder 和 onBindViewHolder调用次数是保持一致的,它们为每个子项都执行了一次。本文开始写的时候,我还草率做了总结。还好,得到了热心网友的指正!

2、然后,我们滑动到底部,打印如下:  

        12-26 17:45:54.449 9860-9860/? D/aaa: onBindViewHolder————小菜一碟(5)
        12-26 17:45:54.469 9860-9860/? D/aaa: onCreateViewHolder————2
        12-26 17:45:54.470 9860-9860/? D/aaa: onBindViewHolder————小菜一碟(6)
        12-26 17:45:54.488 9860-9860/? D/aaa: onCreateViewHolder————2
        12-26 17:45:54.488 9860-9860/? D/aaa: onBindViewHolder————小菜一碟(7)
        12-26 17:45:54.506 9860-9860/? D/aaa: onCreateViewHolder————1
        12-26 17:45:54.506 9860-9860/? D/aaa: onBindViewHolder————主食
        12-26 17:45:54.512 9860-9860/? D/aaa: onBindViewHolder————馒头,嗷~(0)
        12-26 17:45:54.514 9860-9860/? D/aaa: onBindViewHolder————馒头,嗷~(1)
        12-26 17:45:54.516 9860-9860/? D/aaa: onBindViewHolder————馒头,嗷~(2)
        12-26 17:45:54.519 9860-9860/? D/aaa: onBindViewHolder————馒头,嗷~(3)
        12-26 17:45:54.521 9860-9860/? D/aaa: onBindViewHolder————馒头,嗷~(4)
        12-26 17:45:54.541 9860-9860/? D/aaa: onBindViewHolder————馒头,嗷~(5)
        12-26 17:45:54.549 9860-9860/? D/aaa: onCreateViewHolder————2
        12-26 17:45:54.549 9860-9860/? D/aaa: onBindViewHolder————馒头,嗷~(6)
        12-26 17:45:54.554 9860-9860/? D/aaa: onBindViewHolder————馒头,嗷~(7)
        12-26 17:45:54.556 9860-9860/? D/aaa: onBindViewHolder————饮料
        12-26 17:45:54.559 9860-9860/? D/aaa: onBindViewHolder————啤酒饮料矿泉水(0)
        12-26 17:45:54.561 9860-9860/? D/aaa: onBindViewHolder————啤酒饮料矿泉水(1)
        12-26 17:45:54.563 9860-9860/? D/aaa: onBindViewHolder————啤酒饮料矿泉水(2)
        12-26 17:45:54.565 9860-9860/? D/aaa: onBindViewHolder————啤酒饮料矿泉水(3)
        12-26 17:45:54.567 9860-9860/? D/aaa: onBindViewHolder————啤酒饮料矿泉水(4)
        12-26 17:45:54.569 9860-9860/? D/aaa: onBindViewHolder————啤酒饮料矿泉水(5)
        12-26 17:45:54.571 9860-9860/? D/aaa: onBindViewHolder————啤酒饮料矿泉水(6)
        12-26 17:45:54.573 9860-9860/? D/aaa: onBindViewHolder————啤酒饮料矿泉水(7)
        12-26 17:45:54.585 9860-9860/? D/aaa: onBindViewHolder————菜品

3、最后,我们滑动到顶部,打印如下:  

        12-26 17:47:23.099 9860-9860/? D/aaa: onBindViewHolder————主食
        12-26 17:47:23.109 9860-9860/? D/aaa: onBindViewHolder————小菜一碟(7)
        12-26 17:47:23.114 9860-9860/? D/aaa: onBindViewHolder————小菜一碟(6)
        12-26 17:47:23.119 9860-9860/? D/aaa: onBindViewHolder————饮料
        12-26 17:47:23.126 9860-9860/? D/aaa: onBindViewHolder————小菜一碟(5)
        12-26 17:47:23.129 9860-9860/? D/aaa: onBindViewHolder————小菜一碟(4)
        12-26 17:47:23.131 9860-9860/? D/aaa: onBindViewHolder————小菜一碟(3)
        12-26 17:47:23.133 9860-9860/? D/aaa: onBindViewHolder————小菜一碟(2)
        12-26 17:47:23.152 9860-9860/? D/aaa: onCreateViewHolder————2
        12-26 17:47:23.152 9860-9860/? D/aaa: onBindViewHolder————小菜一碟(1)
        12-26 17:47:23.164 9860-9860/? D/aaa: onBindViewHolder————小菜一碟(0)
        12-26 17:47:23.167 9860-9860/? D/aaa: onBindViewHolder————菜品
        12-26 17:47:23.173 9860-9860/? D/aaa: onBindViewHolder————菜品
        12-26 17:47:23.177 9860-9860/? D/aaa: onBindViewHolder————热销零食(7)
        12-26 17:47:23.185 9860-9860/? D/aaa: onBindViewHolder————热销零食(6)
        12-26 17:47:23.187 9860-9860/? D/aaa: onBindViewHolder————热销零食(5)
        12-26 17:47:23.192 9860-9860/? D/aaa: onBindViewHolder————热销推荐
        12-26 17:47:23.195 9860-9860/? D/aaa: onBindViewHolder————热销零食(4)
        12-26 17:47:23.202 9860-9860/? D/aaa: onBindViewHolder————热销零食(3)
        12-26 17:47:23.208 9860-9860/? D/aaa: onBindViewHolder————热销零食(2)
        12-26 17:47:23.216 9860-9860/? D/aaa: onBindViewHolder————热销零食(1)
        12-26 17:47:23.219 9860-9860/? D/aaa: onBindViewHolder————热销零食(0)
        12-26 17:47:23.225 9860-9860/? D/aaa: onBindViewHolder————热销推荐
         

很简单,先来总结一波~~ ^_^

首先,onBindeViewHolder方法的调用时机是item出现(或将要出现)在屏幕上时,这时需要向传入的viewHolder中填充数据等操作。

然后,onCreateViewHolder的目的是创建viewHolder。而viewHolder作为recyclerView缓存管理的对象是可以在列表中复用的。

最后,当屏幕上下滑动,子项移除屏幕viewHolder就会被回收,子项复用时会从缓存池中判断item type再次调用onBindViewHolder方法。


六、Recycle 复用回收机制

(1)复用机制

getViewForPosition()方法是复用机制的入口,也就是 Recycler 开放给外部使用复用机制的api,外部调用这个方法就可以返回想要的 View,而至于这个 View 是复用而来的,还是重新创建得来的,就都由 Recycler 内部实现,对外隐藏。Recycler 两个重要的结构体,用来缓存 ViewHolder 的:

  • ArrayList<ViewHolder> mCachedViews:

滑动过程中的回收和复用都是先处理的这个 List,这个集合里存的 ViewHolder 的原本数据信息都在,所以可以直接添加到 RecyclerView 中显示,不需要再次重新 onBindViewHolder()。只有原来的子项可以重新复用这个 ViewHolder,新位置的子项无法从 mCachedViews 里拿 ViewHolder出来用。

  • ArrayList<ViewHolder> mRecyclerPool:

存在这里的 ViewHolder 的数据信息会被重置掉,相当于 ViewHolder 是一个重创新建的一样。拿到 ViewHolder 之后,还会再次调用 resetInternal() 来重置 ViewHolder,这样 ViewHolder 就可以当作一个全新的 ViewHolder 来使用,所以需要重新调用 onBindViewHolder 来绑定数据。

复用时,先到 mCachedViews 里找 ViewHolder,但需要各种匹配条件,概括一下就是只有原来位置的卡位可以复用存在 mCachedViews 里的 ViewHolder,如果 mCachedViews 里没有,那么才去 ViewPool 里找。

 

(2)回收机制

回收时,逻辑比较简单,由 LayoutManager 遍历移出屏幕的子项,从而对每个子项进行回收操作。

mCachedViews 优先级高于 RecyclerViewPool,回收时都是把 ViewHolder 放在 mCachedViews 里面,如果 mCachedViews 满了,那就在 mCachedViews 里拿一个 ViewHolder 扔到 ViewPool 缓存里,然后 mCachedViews 就可以空出位置来放新回收的 ViewHolder 了。在 ViewPool 里的 ViewHolder 都是跟全新的 ViewHolder 一样,只要 type 一样,有找到,就可以拿出来复用,重新绑定下数据即可。


结尾,送菊花。

最后说一句话,下面一篇文章是把这个案例升级,实现可以吸附在顶部的列表小标题。欢迎各位看官去研究一波。

Android 使用RecycleView实现吸附小标题的Demo(附源码)

 

 

 

  • 23
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

艾阳Blog

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

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

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

打赏作者

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

抵扣说明:

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

余额充值