安卓RecyclerView那些事 - (一)了解RecycleView

转载请附上原博客连接 https://www.jianshu.com/p/69ac902e688c
项目里面需要一个下拉刷新,上滑到底部加载更多的RecyclerView,所以最近又回顾了一下之前的知识,有了一些更深的理解。

RecyclerView的优点

RecyclerView相对于ListView有很多好处,比如:

1.相对于ListView,RecyclerView的效率更高,更符合设计模式。

在ListView中,如果我们不去优化Adapter.getView(int position, View convertView,ViewGroup parent)方法时,每个item滚动到屏幕可见区域时,ListView都会调用Adapter的getView()方法重新加载一下item的布局,这样性能上有很大的损失。通常我们优化ListView是用如下的方法


public class MyAdapter extends ArrayAdapter<data>{
    private List<data> myDataList = new ArrayList<>();
    public MyAdapter(@NonNull Context context, int resource) {
        super(context, resource);
    }
    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        data myData = myDataList.get(position);
        View view;
        ViewHolder viewHolder;
        if(convertView==null){
            view= LayoutInflater.from(getContext()).inflate(R.layout.list_item,parent,false);
            viewHolder=new ViewHolder();
            viewHolder.msg=(TextView)view.findViewById(R.id.msg);
            view.setTag(viewHolder);
        }else{
            view=convertView;
            viewHolder=(ViewHolder) view.getTag();
        }
        viewHolder.msg.setText(myData.getMsg());
        return view;
    }
    class ViewHolder{
        TextView msg;
    }
}

就是我们将item的所有子view缓存在ViewHolder中,并将ViewHolder放入convertView的Tag中。这样在getView的时候我们先判断是否缓存了子view,如果没有缓存,我们在去加载子view。
而在RecyclerView中,RecyclerView自动帮我们完成了View的缓存,创建和数据绑定,我们只需要告诉RecyclerView怎么创建View和绑定数据就行。

2.相对于ListView,RecyclerView更加美观

在RecyclerView中,系统已经为我们定义好了许多,比如:线性布局,网格布局,瀑布布局等。还可以定义滑动的方向,你可以快速地设置横向滑动或者竖向滑动,这些都是ListView没有的。

3.子项的点击

在ListView中为我们预置了点击事件的接口setOnItemClickListener(),不过这个点击事件是整个Item的点击,他是覆盖在item中所有子控件之上的,要为想为item中的每个控件添加点击事件,ListView是比较麻烦的。而RecyclerView中虽然没有为我们预置点击事件,但是我们可以灵活地为item中每个子控件添加点击之间,操作更加精确。

4.可以添加动画

可以控制Item增删的动画,通过ItemAnimator这个类进行控制。

总之,RecyclerView的功能是比ListView强大许多的。

RecyclerView的基本使用方法

1.创建item布局

示例如下

<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:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/msg"
        android:padding="10dp"
        android:text="无信息"
        />
</LinearLayout>

2.创建ViewHolder

ViewHolder的作用就是保存对item的左右子view的引用,用以缓存视图,不用每次都重新创建

public class ViewHolder extends RecyclerView.ViewHolder{
    TextView msg;//保持textView的引用,作为缓存

    public ViewHolder(View itemView) {
        super(itemView);
        msg=(TextView)itemView.findViewById(R.id.msg);
    }
}

3.创建Adapter

Adapter是RecyclerView和ViewHolder之前的桥梁。RecyclerView的每一个item被滚动到屏幕上显示的时候,首先会调用Adapter的getItemCount获得item数量,然后调用onCreateViewHolder来创建视图(并不是没一个item都需要调用onCreateViewHolder,当RecyclerView创建足够多的ViewHolder后,就会复用之前已经创建的ViewHolder,从而提高性能,这一点下面我会进行验证),获得ViewHolder中保存的视图后,最后调用onBindViewHolder为视图绑定数据和事件。这样,一个item就可以显示出来了。Adapter的代码如下

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
    private static final String TAG= "RecyclerAdapter";
    public Context context;

    public List<data> dataList=new ArrayList<>();

    public data mData;

    private TextClickListener clickListener;
    public RecyclerAdapter(Context context,List<data> dataList){
        this.context=context;
        this.dataList=dataList;
    }

    /**
     * 创建viewholder
     * @param parent
     * @param viewType
     * @return
     */
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View item = LayoutInflater.from(context).inflate(R.layout.recycleview_item,parent,false);
        Log.e(TAG,"onCreateViewHolder");
        return new ViewHolder(item);
    }

    /**
     * 绑定数据
     * @param holder
     * @param position
     */
    @Override
    public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
            mData=dataList.get(position);
            ((ViewHolder) holder).msg.setText(mData.getMsg());
            if(clickListener!=null){
                ((ViewHolder) holder).msg.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        clickListener.OnClick(((ViewHolder) holder).msg,position);
                    }
                });
            }
            Log.e(TAG,"onBindViewHolder:"+mData.getMsg());
    }

    @Override
    public int getItemCount() {
        return dataList.size();
    }

    public void setClickListener(TextClickListener clickListener){
        this.clickListener=clickListener;
    }
}

4.使用RecyclerView

在页面布局用引入RecyclerView

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.tinymonster.recycleviewtest1.MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginRight="10dp"
        />
</LinearLayout>

在Activity中使用RecyclerView

public class MainActivity extends AppCompatActivity {
    RecyclerView recyclerView;
    RecyclerAdapter recyclerAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = (RecyclerView)findViewById(R.id.recyclerView);
        recyclerAdapter = new RecyclerAdapter(MainActivity.this,data.getDataList());
        recyclerAdapter.setClickListener(new TextClickListener() {
            @Override
            public void OnClick(View view, int position) {
                Toast.makeText(MainActivity.this,"点击了第"+position+"个item",Toast.LENGTH_SHORT).show();
            }
        });
        recyclerView.setAdapter(recyclerAdapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
    }
}

Adapter中onCreateViewHolder和onBindViewHolder的调用顺序

我们知道ViewHolder中保存了item中的控件的引用,用来缓存item中的控件视图。onCreateViewHolder是创建ViewHolder的,也就是创建item中的控件视图的。onBindViewHolder是为缓存的控件绑定数据的。我们说RecyclerView比ListView的性能更高,是应为RecyclerView重复使用了item的视图,这到底是怎么回事呢?下面我们运行程序,看程序中的打印信息。


image.png

image.png

可以看到在第21个item之前都是先调用onCreateViewHolder,再调用onBindViewHolder。之后便只调用了onBindViewHolder。这是应为刚开始RecyclerView没有积累足够的ViewHolder,所以要一直创建。当RecyclerView积累了足够的ViewHolder后,便会复用之前创建的ViewHolder,仅仅调用onBindViewHolder改变ViewHolder中缓存的视图的数据即可,然后将它作为新的item显示出来。这样就不需要为每个item都重新加载一次视图,达到提高性能的目的。
代码已经上传到GitHub
https://github.com/Tiny-Monster/RecycleViewTest1

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容

  • 内容 抽屉菜单 ListView WebView SwitchButton 按钮 点赞按钮 进度条 TabLayo...
    小狼W阅读 1,596评论 0 10
  • 这篇文章分三个部分,简单跟大家讲一下 RecyclerView 的常用方法与奇葩用法;工作原理与ListView比...
    LucasAdam阅读 4,320评论 0 27
  • 1、概述 Android文档中是这么定义RecyclerView的:*A RecyclerView is a fl...
    高丕基阅读 1,343评论 2 36
  • 概述 随着2014年Google IO的召开,Android L Preview版随之发布,对于开发着来说,带来了...
    小鄧子阅读 35,587评论 33 225
  • “所有的文字和照片都是翻山越岭时留下的标记,我还在继续标记”。 在四月的最后一刻,先发布一篇文章,mark下时间,...
    Echo丽阅读 451评论 2 1