viewholder(listview和recyclerview的区别)

本文目录
- listview和recyclerview的区别
- RecyclerView.ViewHolder onCreateViewHolder一直被调用到为啥
- android 封装recyclerview的adapter时为什么viewholder找不到
- Android的RecycleView. ViewHolder的构造函数是怎样的
- Android ViewHolder的作用与用法
- Android Studio在ViewHolder的子类中调用super(view)的作用是什么
- RecyclerView是如何使用的,阐述ViewHold和adapter的区别
listview和recyclerview的区别
ViewHolder
ViewHolder是用来保存视图引用的类,无论是ListView亦或是RecyclerView。只不过在ListView中,ViewHolder需要自己来定义,且这只是一种推荐的使用方式,不使用当然也可以,这不是必须的。而在RecyclerView中使用RecyclerView.ViewHolder则变成了必须,尽管实现起来稍显复杂,但它却解决了ListView面临的上述不使用自定义ViewHolder时所面临的问题。RecyclerView.ViewHolder被BaseAdapter使用,以将posiiton绑定到上面(可以通过API查看RecyclerView.ViewHolder#getPosition()方法)。
LayoutManager
我们知道ListView只能在垂直方向上滚动,Android API没有提供ListView在水平方向上面滚动的支持。或许有多种方式实现水平滑动,但是请想念我,ListView并不是设计来做这件事情的。但是RecyclerView相较于ListView,在滚动上面的功能扩展了许多。它可以支持多种类型列表的展示要求,主要如下:
1.LinearLayoutManager,可以支持水平和竖直方向上滚动的列表。
2.StaggeredGridLayoutManager,可以支持交叉网格风格的列表,类似于瀑布流或者Pinterest。
3.GridLayoutManager,支持网格展示,可以水平或者竖直滚动,如展示图片的画廊。
3.ItemAnimator
列表动画是一个全新的、拥有无限可能的维度。起初的Android API中,删除或添加item时,item是无法产生动画效果的。后面随着Android的进化,Google的Chat Hasse推荐使用ViewPropertyAnimator属性动画来实现上述需求。
相比较于ListView,RecyclerView.ItemAnimator则被提供用于在RecyclerView添加、删除或移动item时处理动画效果。同时,如果你比较懒,不想自定义ItemAnimator,你还可以使用DefaultItemAnimator。
4.Adapter
ListView的Adapter中,getView是最重要的方法,它将视图跟position绑定起来,是所有神奇的事情发生的地方。同时我们也能够通过registerDataObserver在Adapter中注册一个观察者。RecyclerView也有这个特性,RecyclerView.AdapterDataObserver就是这个观察者。ListView有三个Adapter的默认实现,分别是ArrayAdapter、CursorAdapter和SimpleCursorAdapter。然而,RecyclerView的Adapter则拥有除了内置的内DB游标和ArrayList的支持之外的所有功能。RecyclerView.Adapter的实现的,我们必须采取措施将数据提供给Adapter,正如BaseAdapter对ListView所做的那样
5.OnItemTouchListener
ListView通过AdapterView.OnItemClickListener接口来探测点击事件。而RecyclerView则通过RecyclerView.OnItemTouchListener接口来探测触摸事件。它虽然增加了实现的难度,但是却给予开发人员拦截触摸事件更多的控制权限。
RecyclerView.ViewHolder onCreateViewHolder一直被调用到为啥
思路是:因为ViewHolder我们可以拿到每个Item的根布局,所以如果我们为根布局设置单独的OnClick监听并将其开放给Adapter,那不就可以在组装RecyclerView时就能够设置ItemClickListener,只不过这个Listener不是设置到RecyclerView上而是设置到Adapter。
我们首先看ViewHolder的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class MyViewHolder extends ViewHolder implements OnClickListener,OnLongClickListener{
public ImageView iv;
public TextView tv;
private MyItemClickListener mListener;
private MyItemLongClickListener mLongClickListener;
public MyViewHolder(View rootView,MyItemClickListener listener,MyItemLongClickListener longClickListener) {
super(rootView);
iv = (ImageView)rootView.findViewById(R.id.item_iv);
tv = (TextView)rootView.findViewById(R.id.item_tv);
this.mListener = listener;
this.mLongClickListener = longClickListener;
rootView.setOnClickListener(this);
rootView.setOnLongClickListener(this);
}
/**
* 点击监听
*/
@Override
public void onClick(View v) {
if(mListener != null){
mListener.onItemClick(v,getPosition());
}
}
/**
* 长按监听
*/
@Override
public boolean onLongClick(View arg0) {
if(mLongClickListener != null){
mLongClickListener.onItemLongClick(arg0, getPosition());
}
return true;
}
}《/span》
因为在构造ViewHolder时,rootView将作为一个必传参数传递进来,所以我们只需要拿到rootView并给其绑定点击监听事件即可。
下面要考虑的就是怎样把listener传递进来。Demo中设定了监听点击事件的Interface:MyItemClickListener:
1
2
3
public interface MyItemClickListener {
public void onItemClick(View view,int postion);
}
MyItemClickListener模仿ListView的OnItemClickListener,开放了view和position两个参数,这对习惯使用ListView的开发者们使用起来更得心应手。从ViewHolder的代码中可以看到,执行onClick方法时会调用getPosition()将当前Item的位置回调给listener。getPosition()是ViewHolder的内置方法,可直接使用。
上面提到过,listener是设定到Adapter上的,所以Adapter就需要对外开放相关方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent,false);
MyViewHolder vh = new MyViewHolder(itemView,mItemClickListener,mItemLongClickListener);
return vh;
}
/**
* 设置Item点击监听
* @param listener
*/
public void setOnItemClickListener(MyItemClickListener listener){
this.mItemClickListener = listener;
}
public void setOnItemLongClickListener(MyItemLongClickListener listener){
this.mItemLongClickListener = listener;
android 封装recyclerview的adapter时为什么viewholder找不到
RecyclerView是一种新的视图组,目标是为任何基于适配器的视图提供相似的渲染方式。它被作为ListView和GridView控件的继承者,在最新的support-V7版本中提供支持。在开发RecyclerView时充分考虑了扩展性,因此用它可以创建想到的任何种类的的布局。但在使用上也稍微有些不便。这就是Android——要完成一件事情总不是那么容易。如果使用RecyclerView,你需要了解以下三个元素:RecyclerView.AdapterLayoutManagerItemAnimatorRecyclerView.AdapterRecyclerView包含了一种新型适配器。它与现在使用的适配器类似,但也稍有不同,例如它需要使用ViewHolder。使用时需要重写两个主要方法:一个用来展现视图和它的持有者,而另一个用来把数据绑定到视图上。这么做的好处是,第一种方法只有当我们真正需要创建一个新视图时才被调用,不需要检查它是否已经被回收。LayoutManager这个类决定视图被放在画面中哪个位置,但这只是它的众多职责之一。它可以管理滚动和循环利用。LayoutManager只有一个叫做LinearLayoutManager的实现类,它有1500多行代码。但从这一点就可以看出它有多复杂。管理器可以模拟列表视图(包括横向和纵向),但没有页眉和页尾。为LayoutManager编写子类不太适合新手,我们需要依靠社区来发掘RecyclerView的全部潜力。与这个例子一起,在短时间内我会上传一个GridView控件的实现。我认为这背后的关键是要仿照LinearLayoutManager的代码创建一个BaseLayoutManager,并且基于此进行扩展。或许support-v7的最终版本会提供更多、更好的实现。ItemAnimatorItemAnimator会根据适配器上收到的通知动画显示视图组的修改。基本上,它会自动显示添加和移除条目动画。这也不是一个简单的类,但我们发现DefaultItemAnimator已经可以运行得很好了。
Android的RecycleView. ViewHolder的构造函数是怎样的
1、代码如下:
mAdapter.setOnItemClickListener(new NavAdapter.OnRecyclerViewItemClickListener(){
@Override
public void onItemClick(View view , int position){
Log.v("mainDebug","position:"+position+"");
//重置显示效果
int firstItemPosition=((LinearLayoutManager)mLayoutManager).findFirstVisibleItemPosition();
int lastPos = ((LinearLayoutManager)mLayoutManager).findLastVisibleItemPosition();
System.out.println(firstItemPosition+"——"+lastPos);
for(int i=1;i《mAdapter.getItemCount();i++)
{
View v=mRecyclerView.getChildAt(i);
NavAdapter.ViewHolder viewHolder=(NavAdapter.ViewHolder)mRecyclerView.getChildViewHolder(v);
viewHolder.getmItemText().setTextColor(getResources().getColor(R.color.black));
viewHolder.getmItemIcon().setImageResource(mAdapter.getNormalIcon(i - 1));
}
//设置选中效果
View v=mRecyclerView.getChildAt(position);
NavAdapter.ViewHolder viewHolder=(NavAdapter.ViewHolder)mRecyclerView.getChildViewHolder(v);
viewHolder.getmItemText().setTextColor(getResources().getColor(R.color.mainColor));
viewHolder.getmItemIcon().setImageResource(mAdapter.getSelectedIcon(position - 1));
//提示重绘
mAdapter.notifyDataSetChanged();
}
});
2、我根据点击的position得到View,这一步得到的确实是我说点击的那个view,我已经输出view中的textView内容看过了,没有问题。
3、但是我得到ViewHolder后,去设置文本的颜色,缺发现改变的颜色不是我所点击的那个view的,而是他前面的2个的view的颜色被改变了,不知道该怎么解决。
Android ViewHolder的作用与用法
ViewHolder通常出现在适配器里,为的是listview滚动的时候快速设置值,而不必每次都重新创建很多对象,从而提升性能。
在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局,但当listview有大量的数据需要加载的时候,会占据大量内存,影响性能,这时候就需要按需填充并重新使用view来减少对象的创建。
ListView加载数据都是在public View getView(int position, View convertView,
ViewGroup parent)
{}方法中进行的(要自定义listview都需要重写listadapter:如BaseAdapter,SimpleAdapter,CursorAdapter的等的getvView方法),优化listview的加载速度就要让convertView匹配列表类型,并最大程度上的重新使用convertView。
getview的加载方法一般有以下三种种方式:
最慢的加载方式是每一次都重新定义一个View载入布局,再加载数据
public View getView(int position, View convertView, ViewGroup parent)
{
View item = mInflater.inflate(R.layout.list_item_icon_text,
null);
((TextView)
item.findViewById(R.id.text)).setText(DATA);
((ImageView) item.findViewById(R.id.icon)).setImageBitmap(
(position & 1) == 1 ? mIcon1 : mIcon2);
return item;
}
正确的加载方式是当convertView不为空的时候直接重新使用convertView从而减少了很多不必要的View的创建,然后加载数据
public View getView(int position, View convertView, ViewGroup parent)
{
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item, parent, false);
}
((TextView)
convertView.findViewById(R.id.text)).setText(DATA);
((ImageView)
convertView.findViewById(R.id.icon)).setImageBitmap(
(position & 1) == 1 ? mIcon1 : mIcon2);
return convertView;
}
最快的方式是定义一个ViewHolder,将convetView的tag设置为ViewHolder,不为空时重新使用即可
static class ViewHolder {
TextView text;
ImageView icon;
}
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item_icon_text,
parent, false);
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.text.setText(DATA);
holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 :
mIcon2);
return convertView;
}
***隐藏网址***
Android Studio在ViewHolder的子类中调用super(view)的作用是什么
java中堆栈内存:一个对象的指针被占有,对象是无法销毁的
个人理解:ViewHolder持有ui控件的指针,activity要销毁,但是activity中的ui控件的指针被占有(可以看做viewholder 持有activity 的堆内存地址),activity是无法销毁的。这就造成了内存溢出
ViewHolder不加修饰符 static,那便是隐式外部类
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"?》
***隐藏网址***
***隐藏网址***
***隐藏网址***
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"?》
***隐藏网址***
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为其添加、绑定数据。
而

更多文章:
teammate(teammate,company,partner)
2026年10月11日 06:10
javascript arraybuffer(javascript可以把base64编码转换成二进制代码吗求示例代码!)
2026年10月11日 04:00
text函数公式(excel中round和text函数的区别是什么)
2026年10月11日 03:50
google chrome打不开(chrome浏览器打不开怎么回事 浏览器打不开的处理方法)
2026年10月11日 02:00
websocket整合springboot(Springboot整合Websocket遇到的坑)
2026年10月11日 01:40
drawerlayout(android 怎样让drawerlayout设置的侧滑菜单的内容充满屏幕)
2026年10月10日 19:20
xor四位数怎么运算(单片机怎样用C语言实现4个数字间的异或)
2026年10月10日 17:50
perl数组中最多的元素(用perl实现,得到一个数组中重复次数最多的元素)
2026年10月10日 17:00



