RecyclerView是如何使用的,阐述ViewHold和adapter的区别?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RecyclerView是如何使用的,阐述ViewHold和adapter的区别?相关的知识,希望对你有一定的参考价值。
首先,要明白RecyclerView是做什么的?其次是为什么要用RecyclerView?这里牵扯到RecyclerView和ListView的区别,这里不废话,大家自行百度即可!以下示例我用的android API 29 ,启用了AndroidX。
第一步,添加依赖
创建一个新的工程,在app/build.gradle中的dependencies闭包添加以下内容:
implementation 'com.android.support:appcompat-v7:29.0.0'
注意这里的‘29.0.0’要和你的 compileSdkVersion 版本号一致。版本号是28,就改为28。
别的不需要改,以下是此时的项目目录以及gradle文件内容
第二步,创建RecyclerView布局
在你的布局文件中添加RecyclerView,切记要为RecyclerView添加id。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_card"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
第三步,为RecyclerView中的item创建一个统一的布局文件
在layout下创建一个名为layout_rv_card的布局文件,文件名命名要和你的实际业务相匹配方便后期查找。
在此布局文件中,可以添加任何你想展示的视图,在这里我们先创建两个TextView为大家展示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_id"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center" />
<TextView
android:id="@+id/tv_state"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center" />
</LinearLayout>
别忘了添加id。
第四步,创建Adapter
Adapter是连接后端数据和前端显示的适配器接口,是数据和UI(View)之间一个重要的纽带。
如果之前没有接触过,先跟着做,做完之后就会理解了。
我们在项目目录下新建一个Java类,取名为CardAdapter。
然后在CardAdapter中我们创建一个内部类MyViewHolder继承RecyclerView.ViewHolder。
为什么要创建内部类?
答:就是为了方便而已,创建在外部也是可以,但是如果项目大了之后,类太多不好区分,而且基本上因为布局的不同ViewHolder也基本不同,不会复用,所以创建在内部即可。
为什么要使用ViewHolder?
答:ViewHolder的主要任务:容纳View视图。前边我们提到Adapter连接了后端数据和前端显示,viewHolder的作用就是提供前端的视图文件。
接下来,我们在ViewHolder绑定视图文件,同在activity中类似,itemView顾名思义即列表中每一项的视图,每一项都要绑定。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
/**
* @Author: Messi Mei
* @Date: 2020/8/24 13:46
* @Email: 709909986@qq.com
**/
public class CardAdapter
class MyViewHolder extends RecyclerView.ViewHolder
private TextView tvId,tvState;
public MyViewHolder(@NonNull View itemView)
super(itemView);
tvId = itemView.findViewById(R.id.tv_id);
tvState = itemView.findViewById(R.id.tv_state);
第五步,完成Adapter
在我们创建的CardAdapter类继承我们创建的内部类MyViewHolder,并重写提供的三个方法:
onCreateViewHolder(),onBindViewHolder(),getItemCount()
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
/**
* @Author: Messi Mei
* @Date: 2020/8/24 13:46
* @Email: 709909986@qq.com
**/
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.MyViewHolder>
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
return null;
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position)
@Override
public int getItemCount()
return 0;
class MyViewHolder extends RecyclerView.ViewHolder
private TextView tvId,tvState;
public MyViewHolder(@NonNull View itemView)
super(itemView);
tvId = itemView.findViewById(R.id.tv_id);
tvState = itemView.findViewById(R.id.tv_state);
5.1重写onCreateViewHolder方法,返回我们的内部类MyViewHolder ,此处为将我们的item布局文件和adapter绑定。
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.layout_rv_card,parent,false);
return new MyViewHolder(view);
也可以写为
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_rv_card,parent,false);
return new MyViewHolder(view);
一样的。
5.2为每一项视图,添加数据。
此处holder为你每一项的MyViewHolder对象,position 定位,可以理解为list下标。
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position)
holder.tvId.setText(position);
holder.tvState.setText(position+position);
5.3返回列表大小
@Override
public int getItemCount()
return 0;
第六步,创建数据接口
创建一个List列表(当然也可以是JsonArray),以此为例,我们创一个Card实体类,为List添加该类泛型。
6.1接下来在CardAdapter创建一个带该list的构造器
List<Card> list;
public CardAdapter(List<Card> list)
this.list = list;
6.2在getItemCount方法中返回该列表大小
@Override
public int getItemCount()
return list == null ? 0 : list.size();
6.3在onBindViewHolder方法中绑定真实数据
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position)
holder.tvId.setText(list.get(position).getId());
holder.tvState.setText(list.get(position).getState());
以下为整体代码(文末有我在使用RecycleView中对Adapter的改进代码,如有需要可以参考):
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
/** @Author: Messi Mei @Date: 2020/8/24 13:46 @Email: 709909986@qq.com */
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.MyViewHolder>
private List<Card> list;
public CardAdapter(List<Card> list)
this.list = list;
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_rv_card, parent, false);
return new MyViewHolder(view);
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position)
holder.tvId.setText(list.get(position).getId());
holder.tvState.setText(list.get(position).getState());
@Override
public int getItemCount()
return list == null ? 0 : list.size();
static class MyViewHolder extends RecyclerView.ViewHolder
private TextView tvId, tvState;
MyViewHolder(@NonNull View itemView)
super(itemView);
tvId = itemView.findViewById(R.id.tv_id);
tvState = itemView.findViewById(R.id.tv_state);
第七步,使用RecycleView
在Activity中创建RecycleView对象并绑定视图,创建Adapter对象。
在initData中初始化数据。
package com.mz.myapplication;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity
private RecyclerView recyclerView;
private CardAdapter cardAdapter;
private List<Card> list;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
private void initData()
list = new ArrayList<>();
for (int i = 0; i < 50; i++)
Card card = new Card();
card.setId(i+1+"");
if (i%2 == 1)
card.setState("在线");
else
card.setState("离线");
list.add(card);
private void initView()
recyclerView = findViewById(R.id.rv_card);
cardAdapter = new CardAdapter(list);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(cardAdapter);
至此,运行即可。
如果你想要更复杂的列表布局,在布局文件中加入相应的视图即可,修改完后记得在ViewHolder中加入、绑定相应的视图,在Adapter中的onBindViewHolder为其添加、绑定数据。
而 参考技术A 根据官方的介绍RecyclerView是ListView的升级版,既然如此那RecyclerView必然有它的优点,现就RecylerView相对于ListView的优点罗列如下:
① RecyclerView封装了viewholder的回收复用,也就是说RecyclerView标准化了ViewHolder,编写Adapter面向的是ViewHolder而不再是View了,复用的逻辑被封装了,写起来更加简单。
② 提供了一种插拔式的体验,高度的解耦,异常的灵活,针对一个Item的显示RecyclerView专门抽取出了相应的类,来控制Item的显示,使其的扩展性非常强。例如:你想控制横向或者纵向滑动列表效果可以通过LinearLayoutManager这个类来进行控制(与GridView效果对应的是GridLayoutManager,与瀑布流对应的还StaggeredGridLayoutManager等),也就是说RecyclerView不再拘泥于ListView的线性展示方式,它也可以实现GridView的效果等多种效果。你想控制Item的分隔线,可以通过继承RecyclerView的ItemDecoration这个类,然后针对自己的业务需求去抒写代码。
③ 可以控制Item增删的动画,可以通过ItemAnimator这个类进行控制,当然针对增删的动画,RecyclerView有其自己默认的实现。
深入理解Android RecyclerView的缓存机制
我们知道,RecyclerView在大量数据时依然可以丝滑般顺畅的滑动,那它究竟是怎么实现的呢,而RecyclerView之所以好用得益于它优秀的缓存机制。
我们知道,RecyclerView本身是一个ViewGroup,因此在滑动时就避免不了添加或移除子View(子View通过RecyclerView#Adapter中的onCreateViewHolder创建),如果每次使用子View都要去重新创建,肯定会影响滑动的流畅性,所以RecyclerView通过Recycler来缓存的是ViewHolder(内部包含子View),这样在滑动时可以复用子View,某些条件下还可以复用子View绑定的数据。所以本质上来说,RecyclerView之所以能够实现顺畅的滑动效果,是因为缓存机制,因为缓存减少了重复绘制View和绑定数据的时间,从而提高了滑动时的性能。
一、缓存
1.1、四级缓存
Recycler缓存ViewHolder对象有4个等级,优先级从高到底依次为:
- mAttachedScrap:缓存屏幕中可见范围的ViewHolder;
- mCachedViews:缓存滑动时即将与RecyclerView分离的ViewHolder,默认最大2个;
- ViewCacheExtension:自定义实现的缓存;
- RecycledViewPool :ViewHolder缓存池,可以支持不同的ViewType;
1.1.1 mAttachedScrap
mAttachedScrap存储的是当前屏幕中的
以上是关于RecyclerView是如何使用的,阐述ViewHold和adapter的区别?的主要内容,如果未能解决你的问题,请参考以下文章
Recyclerview 中的 view.GONE 仍然保留空间