moh*_*ary 39 android listview android-arrayadapter android-viewholder
在开发Android程序时; 并且你想要一个ArrayAdapter你可以简单地拥有一个Class(大多数时候使用ViewHolder后缀)或直接膨胀你的convertView并通过id找到你的视图.
那么使用ViewHolder有什么好处?
两个例子都在这里:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = ((Activity)getContext()).getLayoutInflater().inflate(R.layout.row_phrase, null);
}
((TextView) convertView.findViewById(R.id.txtPhrase)).setText("Phrase 01");
}
Run Code Online (Sandbox Code Playgroud)
要么 :
static class ViewHolder {
ImageView leftIcon;
TextView upperLabel;
TextView lowerLabel;
}
Run Code Online (Sandbox Code Playgroud)
最后在getView中:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (view == null) {
view = LayoutInflater.from(context).inflate(R.layout.row_layout,
null, false);
holder = new ViewHolder();
holder.leftIcon = (ImageView) view.findViewById(R.id.leftIcon);
}
}
Run Code Online (Sandbox Code Playgroud)
Rag*_*dan 36
了解listview回收的工作原理
您无法回收当前正在使用的行.以上链接解释了listview回收机制的工作原理
那么使用ViewHolder有什么好处?
引用文档
findViewById()在滚动ListView期间,您的代码可能会频繁调用,这会降低性能.即使适配器返回一个膨胀的视图以进行回收,您仍然需要查找元素并更新它们.绕过重复使用的方法findViewById()是使用"视图持有者"设计模式.
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) { // if convertView is null
convertView = mInflater.inflate(R.layout.mylayout,
parent, false);
holder = new ViewHolder();
// initialize views
convertView.setTag(holder); // set tag on view
} else {
holder = (ViewHolder) convertView.getTag();
// if not null get tag
// no need to initialize
}
//update views here
return convertView;
}
Run Code Online (Sandbox Code Playgroud)
你错过了重要的部分convertView.setTag(holder)和holder = (ViewHolder) ConvertView.getTag()
http://developer.android.com/training/improving-layouts/smooth-scrolling.html
ata*_*ulm 18
当您浏览ListView时,在任何给定时间都只显示少量视图.这意味着您不必为适配器中的每个项实例化视图; 当视图在屏幕外滚动时,可以重复使用或回收.
查看回收和ViewHolder模式不一样.ViewHolder模式仅用于减少view.findViewById(int)您拨打的电话数量.ViewHolder模式仅在您利用视图回收时才起作用.
在getView(int position, View convertView, ViewGroup parent)中,convertView参数是要么空,或者它已经回收一个观点:它仍然会从绑定到一个不同的列表项拥有的数据.
如果没有ViewHolder模式,您仍然可以利用视图回收(即不盲目实例化视图):
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
view = // inflate new view
}
ImageView imageView = (ImageView) view.findViewById(R.id.listitem_image);
TextView textView = (TextView) view.findViewById(R.id.listitem_text);
TextView timestampView = (TextView) view.findViewById(R.id.listitem_timestamp);
ProgressBar progressSpinnerView = (ProgressBar) view.findViewById(R.id.progress_spinner);
// TODO: set correct data for this list item
// imageView.setImageDrawable(...)
// textView.setText(...)
// timestampView.setText(...)
// progressSpinnerView.setProgress(...)
return view;
}
Run Code Online (Sandbox Code Playgroud)
以上是视图回收的示例 - 我们不会为每行充气新视图; 如果我们没有给予重用,我们只会给视图充气.在滚动列表时,避免必须给视图充气是肯定有助于提高性能的部分:利用视图回收.
那么ViewHolder当时是什么?我们目前正在findViewById(int)为每个项目做4次,无论行本身是否已经存在.当findViewById(int)递归迭代ViewGroup直到找到具有给定ID的后代时,这对于我们的回收视图来说有点无意义 - 我们正在重新查找我们已经引用的视图.
通过使用ViewHolder对象在"找到"它们之后保存对子视图的引用来避免这种情况:
private static class ViewHolder {
final TextView text;
final TextView timestamp;
final ImageView icon;
final ProgressBar progress;
ViewHolder(TextView text, TextView timestamp, ImageView icon, ProgressBar progress) {
this.text = text;
this.timestamp = timestamp;
this.icon = icon;
this.progress = progress;
}
}
Run Code Online (Sandbox Code Playgroud)
View.setTag(Object)允许您告诉视图保存任意对象.如果我们在执行findViewById(int)调用后使用它来保存ViewHolder的实例,那么我们可以使用View.getTag()回收的视图来避免不得不一次又一次地进行调用.
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
view = // inflate new view
ViewHolder holder = createViewHolderFrom(view);
view.setTag(holder);
}
ViewHolder holder = view.getTag();
// TODO: set correct data for this list item
// holder.icon.setImageDrawable(...)
// holder.text.setText(...)
// holder.timestamp.setText(...)
// holder.progress.setProgress(...)
return view;
}
private ViewHolder createViewHolderFrom(View view) {
ImageView icon = (ImageView) view.findViewById(R.id.listitem_image);
TextView text = (TextView) view.findViewById(R.id.listitem_text);
TextView timestamp = (TextView) view.findViewById(R.id.listitem_timestamp);
ProgressBar progress = (ProgressBar) view.findViewById(R.id.progress_spinner);
return new ViewHolder(text, timestamp, icon, progress);
}
Run Code Online (Sandbox Code Playgroud)
这种优化的性能优势值得怀疑,但这是ViewHolder的优势所在.
mar*_*inj 14
ViewHolder设计模式用于加速你的渲染ListView- 实际上是为了使它顺利运行,findViewById非常昂贵(它进行DOM解析),每次渲染列表项时都使用它,它必须遍历你的布局层次结构并实例化对象.由于列表可以在滚动期间非常频繁地重绘其项目,因此这种开销可能很大.
你可以找到它的工作原理的很好的解释:
http://www.youtube.com/watch?v=wDBM6wVEO70&feature=youtu.be&t=7m
从第10分钟开始,您已经通过谷歌专家解释了ViewHolder的设计模式.
[编辑]
findViewById没有实例化新对象,它只遍历层次结构 - 这里是参考http://androidxref.com/5.1.1_r6/xref/frameworks/base/core/java/android/view/ViewGroup.java#3610
| 归档时间: |
|
| 查看次数: |
43378 次 |
| 最近记录: |