有点新手问题。我们为什么要初始化getView()
中的ViewHolder
?为什么我们不能在构造函数中初始化它?ViewHolder - 良好做法
回答
您将有多个ViewHolder
对象存在。
A ListView
其性质不会为其每行创建新的View
实例。这是如此,如果你有一百万件事情的ListView
,你不需要存储一百万件布局信息。那么你需要存储什么?只是在屏幕上的东西。然后,您可以重复使用这些视图。这样,您的ListView
百万个对象可能只有10个子视图。
在您的自定义阵列适配器,你将有一个名为getView()
功能,看起来是这样的:
public View getView(int position, View convertView, ViewGroup parent) {
//Here, position is the index in the list, the convertView is the view to be
//recycled (or created), and parent is the ListView itself.
//Grab the convertView as our row of the ListView
View row = convertView;
//If the row is null, it means that we aren't recycling anything - so we have
//to inflate the layout ourselves.
if(row == null) {
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.list_item, parent, false);
}
//Now either row is the recycled view, or one that we've inflated. All that's left
//to do is set the data of the row. In this case, assume that the row is just a
//simple TextView
TextView textView = (TextView) row.findViewById(R.id.listItemTextView);
//Grab the item to be rendered. In this case, I'm just using a string, but
//you will use your underlying object type.
final String item = getItem(position);
textView.setText(item);
//and return the row
return row;
}
这是可行的,但需要一些时间,看看你是否可以在这里发现的低效率。考虑一下上面哪段代码会被重复调用。
问题是,我们一次又一次地打电话给row.findViewById
,即使第一次查找它后,它永远不会改变。如果你的列表中只有一个简单的TextView
,那么它可能并不是那么糟糕,如果你有一个复杂的布局,或者你有多个你想要设置数据的视图,你可能会失去一些时间来查找你的视图,再次。
那么我们如何解决这个问题呢?那么,在我们查看之后将TextView存储在某个地方是有意义的。所以我们引入一个名为ViewHolder
的类,它可以“保留”视图。所以适配器的内部,引入一个内部类,像这样:
private static class ViewHolder {
TextView textView;
}
这个类是私有的,因为它只是一个适配器一个缓存机制,所以我们并不需要的参考它是静态的适配器来使用它。
这将存储我们的视图,以便我们不必多次拨打row.findViewById
。我们应该在哪里设置它?当我们第一次夸大观点时。我们在哪里存储它?视图有一个自定义的“标签”字段,可用于存储关于视图的元信息 - 正是我们想要的!然后,如果我们已经看到了这种观点,我们只需要查找的标签,而不是查找每个行内观点..
所以getView()
内部的if语句变成:
//If the row is null, it means that we aren't recycling anything - so we have
//to inflate the layout ourselves.
ViewHolder holder = null;
if(row == null) {
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.list_item, parent, false);
//Now create the ViewHolder
holder = new ViewHolder();
//and set its textView field to the proper value
holder.textView = (TextView) row.findViewById(R.id.listItemTextView);
//and store it as the 'tag' of our view
row.setTag(holder);
} else {
//We've already seen this one before!
holder = (ViewHolder) row.getTag();
}
现在,我们只需更新holder.textView的文本值,因为它已经是对回收视图的引用了!所以我们的最终适配器代码变为:
public View getView(int position, View convertView, ViewGroup parent) {
//Here, position is the index in the list, the convertView is the view to be
//recycled (or created), and parent is the ListView itself.
//Grab the convertView as our row of the ListView
View row = convertView;
//If the row is null, it means that we aren't recycling anything - so we have
//to inflate the layout ourselves.
ViewHolder holder = null;
if(row == null) {
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.list_item, parent, false);
//Now create the ViewHolder
holder = new ViewHolder();
//and set its textView field to the proper value
holder.textView = (TextView) row.findViewById(R.id.listItemTextView);
//and store it as the 'tag' of our view
row.setTag(holder);
} else {
//We've already seen this one before!
holder = (ViewHolder) row.getTag();
}
//Grab the item to be rendered. In this case, I'm just using a string, but
//you will use your underlying object type.
final String item = getItem(position);
//And update the ViewHolder for this View's text to the correct text.
holder.textView.setText(item);
//and return the row
return row;
}
我们完成了!
有些事情要考虑:
- 如何做到这一点的变化,如果你有要更改行多个视图?作为一个挑战,让一个ListView每行有两个
TextView
对象和ImageView
- 当调试的ListView,查了几件事情,让你可以真正看到发生了什么事情:
- 多少次ViewHolder的构造函数被调用。
- 的
holder.textView.getText()
价值是什么,你在getView()
正如我们每次滚动列表时填充行并为每行创建新行视图,我们都需要初始化视图持有者。就像我有两行TextView然后,
static class ViewHolder {
protected TextView title;
protected TextView type;
}
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
if (convertView == null) {
LayoutInflater inflator = context.getLayoutInflater();
view = inflator.inflate(R.layout.feeds_rowview, null);
final ViewHolder viewHolder = new ViewHolder();
view.setTag(viewHolder);
viewHolder.title = (TextView) view.findViewById(R.id.Title);
viewHolder.type = (TextView) view.findViewById(R.id.Type);
} else {
view = convertView;
}
ViewHolder holder = (ViewHolder) view.getTag();
holder.title.setText(list.get(position).getTitle());
holder.type.setText(list.get(position).getType());
return view;
}
不,每个视图都有不同的值。因为我们在行中有不同的数据。 –
- 1. jquery良好做法
- 2. 良好做法MVC
- 3. MVVM的良好做法?
- 4. 良好做法在Perl
- 5. 良好做法:JDBC连接
- 6. IOS FMDB良好做法
- 7. $ elemMatch和良好做法
- 8. 继承和良好做法
- 9. 演员的良好做法?
- 10. 良好的做法或不好的做法
- 11. Bundle Node.js后端 - 良好的做法或不好的做法?
- 12. ASP.NET MVC视图模型良好做法
- 13. 日志记录良好做法
- 14. 排版模板或良好做法
- 15. 良好的做法默认值
- 16. 条件声明中的良好做法
- 17. 宁静的API,良好的做法
- 18. 识别iCloud coreData更新:良好做法
- 19. CSS的良好做法 - 每页一页?
- 20. 使用表格的良好做法
- 21. 的IEnumerable和良好做法(WCF)
- 22. 使用#define,良好的做法?
- 23. Bootstrap网格布局良好做法
- 24. CodeIgniter:表单验证良好做法
- 25. 定义PHP类时的良好做法
- 26. 编写junit测试的良好做法
- 27. iPhone应用文档的良好做法
- 28. ASP.NET MVC - DbContext的良好做法
- 29. 静态存储库:良好的做法?
- 30. html的CSS设计良好的做法?
http://www.youtube.com/watch?v=wDBM6wVEO70年底更新之前。看看这个视频。应该回答你的问题。 – Raghunandan