Suv*_*ica 49 android listview android-adapter
我总是使用LayoutInflater
和findViewById
在一个getView
方法中创建新项目Adapter
.
但在许多文章中,人们写的findViewById
非常慢,强烈建议使用View Holder Pattern.
谁能解释为什么findViewById
这么慢?为什么View Holder Pattern更快?
如果需要添加不同的项目,我该怎么办ListView
?我应该为每种类型创建类吗?
static class ViewHolderItem1 {
TextView textViewItem;
}
static class ViewHolderItem2 {
Button btnViewItem;
}
static class ViewHolderItem3 {
Button btnViewItem;
ImageView imgViewItem;
}
Run Code Online (Sandbox Code Playgroud)
Sim*_*iak 85
谁能解释为什么findViewById这么慢?为什么View Holder Pattern更快?
当您不使用Holder时,getView()
方法将调用findViewById()
多次,因为您的行将不在View中.因此,如果List中有1000行,而990行将不在View中,那么将findViewById()
再次调用990次.
持有者设计模式用于视图缓存 - 持有者(任意)对象保存每行的子窗口小部件,当行超出视图时,将不会调用findViewById()但是将回收View并从Holder获取窗口小部件.
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());
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
正如@meredrica所指出的,如果你想获得更好的性能,你可以使用公共字段(但它会破坏封装).
这是第二种方法如何使用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;
}
Run Code Online (Sandbox Code Playgroud)
众所周知,Google和AppCompat v7作为支持库发布了名为RecyclerView的新ViewGroup ,旨在呈现任何基于适配器的视图.正如@antonioleiva在帖子中所说:"它被认为是ListView和GridView的继承者".
为了能够使用这个元素,你需要一个最重要的东西,它是特殊类型的适配器,包含在上面提到的ViewGroup - RecyclerView.Adapter中,其中ViewHolder是我们在这里讨论的东西:)简单地说,这个新的ViewGroup元素有实现了自己的ViewHolder模式.您需要做的就是创建自定义ViewHolder类,该类必须从RecyclerView.ViewHolder扩展,您无需关心检查适配器中的当前行是否为null.
适配器将为您完成,您可以确保只有在必须充气的情况下才会对行进行充气(我会说).这是一个简单的实现:
public static class ViewHolder extends RecyclerView.ViewHolder {
private TextView title;
public ViewHolder(View root) {
super(root);
title = root.findViewById(R.id.title);
}
}
Run Code Online (Sandbox Code Playgroud)
这里有两件重要事情:
并在适配器中使用ViewHolder.Adapter有三种方法你必须实现:
一个小例子:
@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;
}
Run Code Online (Sandbox Code Playgroud)
1值得一提的是,RecyclerView不提供直接界面来监听项目点击事件.这对某些人来说可能很奇怪,但这里有一个很好的解释为什么它不像实际看起来那么好奇.
我通过创建自己的界面来解决这个问题,该界面用于处理行上的点击事件(以及您想要的任何类型的小部件):
public interface RecyclerViewCallback<T> {
public void onItemClick(T item, int position);
}
Run Code Online (Sandbox Code Playgroud)
我通过构造函数将它绑定到Adapter,然后在ViewHolder中调用该回调:
root.setOnClickListener(new View.OnClickListener {
@Override
public void onClick(View v) {
int position = getPosition();
mCallback.onItemClick(mItems.get(position), position);
}
});
Run Code Online (Sandbox Code Playgroud)
这是基本的例子,所以不要只把它作为一种可能的方式.可能性是无穷无尽的.
ViewHolder模式将创建ViewHolder的静态实例,并在第一次加载时将其附加到视图项,然后将在未来调用时从该视图标记中检索它.因为我们知道getView()方法被非常频繁地调用,特别是当listview中的许多元素被滚动时,实际上每次listview项在滚动时变得可见时都会调用它.
ViewHolder Pattern将阻止findViewById()
被调用很多次无用,将视图保留在静态引用上,这是保存一些资源的好模式(特别是当你需要在listview项目中引用许多视图时).
很好地说 @RomainGuy
ViewHolder可以而且也应该用于存储临时数据结构,以避免在getView()中进行内存分配.ViewHolder包含一个char缓冲区,以避免从Cursor获取数据时的分配.
归档时间: |
|
查看次数: |
32693 次 |
最近记录: |