gpt4 book ai didi

android - ListView 适配器中的 findViewById 与 View Holder 模式

转载 作者:IT王子 更新时间:2023-10-28 23:44:39 24 4
gpt4 key购买 nike

我总是使用 LayoutInflaterfindViewByIdAdaptergetView 方法中创建新项目。

但在很多文章中,人们写到 findViewById 非常非常慢,强烈建议使用 View Holder Pattern。

谁能解释为什么 findViewById 这么慢?为什么 View Holder 模式更快?

如果需要向 ListView 添加不同的项目,我应该怎么做?我应该为每种类型创建类吗?

static class ViewHolderItem1 {
TextView textViewItem;
}

static class ViewHolderItem2 {
Button btnViewItem;
}
static class ViewHolderItem3 {
Button btnViewItem;
ImageView imgViewItem;
}

最佳答案

Can anyone explain why findViewById is so slow? And why View Holder Pattern is faster?

当您不使用 Holder 时,getView() 方法将调用 findViewById() 的次数与您的行不在 View 中一样多。因此,如果您在 List 中有 1000 行并且 990 行将不在 View 范围内,那么将再次调用 990 次 findViewById()

Holder 设计模式用于 View 缓存 - Holder(任意)对象保存每一行的子小部件,当行超出 View 时 findViewById() 不会被调用,但 View 将被回收,小部件将从持有人。

if (convertView == null) {
convertView = inflater.inflate(layout, null, false);
holder = new Holder(convertView);
convertView.setTag(holder); // setting Holder as arbitrary object for row
}
else { // view recycling
// row already contains Holder object
holder = (Holder) convertView.getTag();
}

// set up row data from holder
titleText.setText(holder.getTitle().getText().toString());

Holder 类可以如下所示:

public class Holder {

private View row;
private TextView title;

public Holder(View row) {
this.row = row;
}

public TextView getTitle() {
if (title == null) {
title = (TextView) row.findViewById(R.id.title);
}
return title;
}
}

正如@meredrica 指出的那样,如果您想获得更好的性能,您可以使用公共(public)字段(但它会破坏封装)。

更新:

这里是第二种方法如何使用 ViewHolder 模式:

ViewHolder holder;
// view is creating
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.row, parent, false);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.title);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
convertView.setTag(holder);
}
// view is recycling
else {
holder = (ViewHolder) convertView.getTag();
}

// set-up row
final MyItem item = mItems.get(position);
holder.title.setText(item.getTitle());
...

private static class ViewHolder {

public TextView title;
public ImageView icon;
}

更新 #2:

众所周知,Google 和 AppCompat v7 作为支持库发布了名为 RecyclerView 的新 ViewGroup专为呈现任何基于适配器的 View 而设计。正如 @antonioleivapost 中所说:“应该是ListView和GridView的继承者”

为了能够使用这个元素,你基本上需要一个最重要的东西,它是一种特殊的适配器,包装在提到的 ViewGroup 中 - RecyclerView.Adapter 其中 ViewHolder 就是我们正在谈论的东西这里 :) 简单地说,这个新的 ViewGroup 元素实现了自己的 ViewHolder 模式。您需要做的就是创建必须从 RecyclerView.ViewHolder 扩展的自定义 ViewHolder 类,并且您不需要关心检查适配器中的当前行是否为空。

适配器会为你做这件事,你可以确定只有在必须膨胀的情况下才会膨胀该行(我会说)。这是简单的实现:

public static class ViewHolder extends RecyclerView.ViewHolder {

private TextView title;

public ViewHolder(View root) {
super(root);
title = root.findViewById(R.id.title);
}
}

这里有两件重要的事情:

  • 你必须调用 super() 构造函数,你需要在其中传递你的行的 Root View
  • 您可以直接从 ViewHolder 获取行的特定位置通过 getPosition() 方法。当你想做一些事情时,这很有用在行小部件上点击1 后的操作。

以及适配器中 ViewHolder 的用法。适配器有三个你必须实现的方法:

  • onCreateViewHolder() - 创建 ViewHolder 的位置
  • onBindViewHolder() - 更新行的位置。我们可以说是您正在回收行的一段代码
  • getItemCount() - 我会说它与典型的 getCount() 方法相同在 BaseAdapter 中

举个小例子:

@Override 
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View root = LayoutInflater.from(mContext).inflate(myLayout, parent, false);
return new ViewHolder(root);
}

@Override public void onBindViewHolder(ViewHolder holder, int position) {
Item item = mItems.get(position);
holder.title.setText(item.getTitle());
}

@Override public int getItemCount() {
return mItems != null ? mItems.size() : 0;
}

1 值得一提的是,RecyclerView 没有提供直接接口(interface)来监听项目点击事件。这可能会让某些人感到好奇,但 here is nice explanation为什么它不像实际看起来那么好奇。

我通过创建自己的界面来解决这个问题,该界面用于处理行上的点击事件(以及您想要的任何类型的小部件):

public interface RecyclerViewCallback<T> {

public void onItemClick(T item, int position);
}

我通过构造函数将其绑定(bind)到 Adapter,然后在 ViewHolder 中调用该回调:

root.setOnClickListener(new View.OnClickListener {
@Override
public void onClick(View v) {
int position = getPosition();
mCallback.onItemClick(mItems.get(position), position);
}
});

这是一个基本的例子,所以不要把它当作一种可能的方式。无限可能。

关于android - ListView 适配器中的 findViewById 与 View Holder 模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19289812/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com