android holder 内部类,Android RecyclerView中的ViewHolder

在使用android提供的组件以列表的格式显示数据时,使用过ListView组件和RecyclerView组件。目前一般推荐使用RecyclerView,因为RecyclerView本身的缓存和效率比ListView高,且支持灵活的布局方式,所以会被大家采用。相信大家在使用ListView时,如果要显示的数据多,肯定多会想到优化Adaper的getView()方法,下面给出一个例子:

public class UsersAdapter extends ArrayAdapter {

private static class ViewHolder {

TextView name;

TextView home;

}

public UsersAdapter(Context context, ArrayList users) {

super(context, R.layout.item_user, users);

}

@Override

public View getView(int position, View convertView, ViewGroup parent) {

User user = getItem(position);

ViewHolder viewHolder;

if (convertView == null) {

viewHolder = new ViewHolder();

LayoutInflater inflater = LayoutInflater.from(getContext());

convertView = inflater.inflate(R.layout.item_user, parent, false);

viewHolder.name = (TextView) convertView.findViewById(R.id.tvName);

viewHolder.home = (TextView)convertView.findViewById(R.id.tvHome);

convertView.setTag(viewHolder);

} else {

viewHolder = (ViewHolder) convertView.getTag();

}

viewHolder.name.setText(user.name);

viewHolder.home.setText(user.hometown);

return convertView;

}

}

在这边,我们在ListView需要用到的Adapter中定义了一个内部类ViewHolder,它存储了我们要加载的view的所有子view结构,如果这个view已经被加载过只是暂时被回收, 当需要再次展示的话我们就不需要重新加载整个view,也不需要通过findViewById()来寻找要加载的view的子view,可以直接找到这个view,将要展示的数据设置即可返回显示。

但是在RecyclerView中,我们并不需要做这么多,我们先看一个RecyclerView的简单使用步骤:

定义一个RecyclerView的布局文件以及要展示的item的布局文件

android:orientation="vertical" android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/t_classList"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:orientation="vertical" android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_marginStart="20dp"

android:layout_marginLeft="20dp">

android:id="@+id/t_class_name"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center_vertical"

android:textSize="19sp" />

android:layout_width="match_parent"

android:layout_height="0.5px"

android:background="@color/whiteGray"

android:layout_marginTop="6dp"

android:layout_marginBottom="6dp"

android:typeface="serif"/>

定义一个adapter

public class ClassAdapter extends RecyclerView.Adapter {

private List classVOs;

static class ClassViewHolder extends RecyclerView.ViewHolder {

View classView;

TextView className;

public ClassViewHolder(View itemView) {

super(itemView);

classView = itemView;

className = (TextView) itemView.findViewById(R.id.t_class_name);

}

}

public ClassAdapter(List classVOs){

this.classVOs = classVOs;

}

@Override

public ClassViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragement_class_item, null, false);

final ClassViewHolder holder = new ClassViewHolder(view);

holder.classView.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

int position = holder.getAdapterPosition();

ClassVO classVO = classVOs.get(position);

Toast.makeText(view.getContext(), "you click class "+classVO.getId(), Toast.LENGTH_SHORT).show();

}

});

return holder;

}

@Override

public void onBindViewHolder(ClassViewHolder holder, int position) {

ClassVO classVO = classVOs.get(position);

holder.className.setText(classVO.getName());

}

@Override

public int getItemCount() {

return classVOs.size();

}

}

设置RecyclerView的布局和adapter

recyclerView = (RecyclerView) classListView.findViewById(R.id.t_classList);

layoutManager = new LinearLayoutManager(this.getContext());

recyclerView.setLayoutManager(layoutManager);

if (classVOs!=null){

adapter = new ClassAdapter(classVOs);

}

recyclerView.setAdapter(adapter);

既然我们要说的是RecyclerView中的ViewHolder,但是我们的使用步骤中并没有单独提出ViewHolder,因为在我们上面说的使用步骤的第二步———“定义一个adapter”,就涉及到ViewHolder。

当我们自定义一个adapter时,继承了RecyclerView的一个内部类:

/**

* Base class for an Adapter

*

*

Adapters provide a binding from an app-specific data set to views that are displayed

* within a {@link RecyclerView}.

*/

public static abstract class Adapter {

private final AdapterDataObservable mObservable = new AdapterDataObservable();

private boolean mHasStableIds = false;

/**

* Called when RecyclerView needs a new {@link ViewHolder} of the given type to represent

* an item.

*

* This new ViewHolder should be constructed with a new View that can represent the items

* of the given type. You can either create a new View manually or inflate it from an XML

* layout file.

*

* The new ViewHolder will be used to display items of the adapter using

* {@link #onBindViewHolder(ViewHolder, int, List)}. Since it will be re-used to display

* different items in the data set, it is a good idea to cache references to sub views of

* the View to avoid unnecessary {@link View#findViewById(int)} calls.

*

* @param parent The ViewGroup into which the new View will be added after it is bound to

* an adapter position.

* @param viewType The view type of the new View.

*

* @return A new ViewHolder that holds a View of the given view type.

* @see #getItemViewType(int)

* @see #onBindViewHolder(ViewHolder, int)

*/

public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);

/**

* Called by RecyclerView to display the data at the specified position. This method should

* update the contents of the {@link ViewHolder#itemView} to reflect the item at the given

* position.

*

* Note that unlike {@link android.widget.ListView}, RecyclerView will not call this method

* again if the position of the item changes in the data set unless the item itself is

* invalidated or the new position cannot be determined. For this reason, you should only

* use the position parameter while acquiring the related data item inside

* this method and should not keep a copy of it. If you need the position of an item later

* on (e.g. in a click listener), use {@link ViewHolder#getAdapterPosition()} which will

* have the updated adapter position.

*

* Override {@link #onBindViewHolder(ViewHolder, int, List)} instead if Adapter can

* handle efficient partial bind.

*

* @param holder The ViewHolder which should be updated to represent the contents of the

* item at the given position in the data set.

* @param position The position of the item within the adapter's data set.

*/

public abstract void onBindViewHolder(VH holder, int position);

/**

* Called by RecyclerView to display the data at the specified position. This method

* should update the contents of the {@link ViewHolder#itemView} to reflect the item at

* the given position.

*

* Note that unlike {@link android.widget.ListView}, RecyclerView will not call this method

* again if the position of the item changes in the data set unless the item itself is

* invalidated or the new position cannot be determined. For this reason, you should only

* use the position parameter while acquiring the related data item inside

* this method and should not keep a copy of it. If you need the position of an item later

* on (e.g. in a click listener), use {@link ViewHolder#getAdapterPosition()} which will

* have the updated adapter position.

*

* Partial bind vs full bind:

*

* The payloads parameter is a merge list from {@link #notifyItemChanged(int, Object)} or

* {@link #notifyItemRangeChanged(int, int, Object)}. If the payloads list is not empty,

* the ViewHolder is currently bound to old data and Adapter may run an efficient partial

* update using the payload info. If the payload is empty, Adapter must run a full bind.

* Adapter should not assume that the payload passed in notify methods will be received by

* onBindViewHolder(). For example when the view is not attached to the screen, the

* payload in notifyItemChange() will be simply dropped.

*

* @param holder The ViewHolder which should be updated to represent the contents of the

* item at the given position in the data set.

* @param position The position of the item within the adapter's data set.

* @param payloads A non-null list of merged payloads. Can be empty list if requires full

* update.

*/

可以看到,RecyclerView内部已经帮我们定义好了ViewHolder抽象类,当我们自定义Adapter时,需要定义好要继承ViewHolder的类(Adapter)。

ViewHolder的作用我们在上文介绍使使用ListView时已经说到,简而言之就是提高消息,下面我们看一看源码中对ViewHolder的介绍:

/**

* A ViewHolder describes an item view and metadata about its place within the RecyclerView.

*

*

{@link Adapter} implementations should subclass ViewHolder and add fields for caching

* potentially expensive {@link View#findViewById(int)} results.

*

*

While {@link LayoutParams} belong to the {@link LayoutManager},

* {@link ViewHolder ViewHolders} belong to the adapter. Adapters should feel free to use

* their own custom ViewHolder implementations to store data that makes binding view contents

* easier. Implementations should assume that individual item views will hold strong references

* to ViewHolder objects and that RecyclerView instances may hold

* strong references to extra off-screen item views for caching purposes

*/

public static abstract class ViewHolder {

......

}

可以看出两点重要的地方:

Adapter implementations should subclass ViewHolder and add fields for caching potentially expensive {@link View#findViewById(int)} results(adapter应当拥有ViewHolder的子类,并且ViewHolder内部应当存储一些子view,避免时间代价很大的findViewById操作)

Adapters should feel free to use their own custom ViewHolder implementations to store data that makes binding view content easier

其RecyclerView内部定义的ViewHolder类包含很多复杂的属性,内部使用场景也有很多,而我们经常使用的也就是onCreateViewHolder()方法和onBindViewHolder()方法,onCreateViewHolder()方法在RecyclerView需要一个新类型。item的ViewHolder时调用来创建一个ViewHolder,而onBindViewHolder()方法则当RecyclerView需要在特定位置的item展示数据时调用。

参考文章:

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android RecyclerView 是一个非常常用的控件,用于展示大量的数据列表。在使用 RecyclerView 时,我们需要创建 ViewHolder 和 Adapter。 ViewHolder 是一个容器,用于存放 RecyclerView 的每个 item 的视图,我们可以在其找到 item 的各个控件。Adapter 则是将数据与 ViewHolder 绑定在一起,用于将数据显示在 RecyclerView 上。 在 RecentApp ,我们可以按照以下步骤使用 RecyclerViewViewHolder 和 Adapter: 1. 在 XML 布局文件添加 RecyclerView 控件: ``` <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 2. 创建 ViewHolder 类,用于存放 RecyclerView 的 item 视图: ``` public class RecentAppViewHolder extends RecyclerView.ViewHolder { public TextView appName; public ImageView appIcon; public RecentAppViewHolder(@NonNull View itemView) { super(itemView); appName = itemView.findViewById(R.id.app_name); appIcon = itemView.findViewById(R.id.app_icon); } } ``` 3. 创建 Adapter 类,用于将数据与 ViewHolder 绑定在一起: ``` public class RecentAppAdapter extends RecyclerView.Adapter<RecentAppViewHolder> { private List<AppInfo> appInfoList; public RecentAppAdapter(List<AppInfo> appInfoList) { this.appInfoList = appInfoList; } @NonNull @Override public RecentAppViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_recent_app, parent, false); return new RecentAppViewHolder(view); } @Override public void onBindViewHolder(@NonNull RecentAppViewHolder holder, int position) { AppInfo appInfo = appInfoList.get(position); holder.appName.setText(appInfo.getName()); holder.appIcon.setImageDrawable(appInfo.getIcon()); } @Override public int getItemCount() { return appInfoList.size(); } } ``` 4. 在 Activity 或 Fragment 初始化 RecyclerViewViewHolder 和 Adapter: ``` RecyclerView recyclerView = findViewById(R.id.recycler_view); RecentAppAdapter adapter = new RecentAppAdapter(appInfoList); recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); ``` 这样,就可以在 RecentApp 使用 RecyclerViewViewHolder 和 Adapter 来显示最近打开的应用程序了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值