我今天学习了Android的ArrayAdapter,发现有一个通用模式,它使用ViewHolder来保存Views的引用,而不是每次调用findViewById。为什么ViewHolder模式有效?
但它是如何工作的?适配器通常用于显示视图(组)的列表,如果我缓存视图,为什么他们都不参考最老的?
我今天学习了Android的ArrayAdapter,发现有一个通用模式,它使用ViewHolder来保存Views的引用,而不是每次调用findViewById。为什么ViewHolder模式有效?
但它是如何工作的?适配器通常用于显示视图(组)的列表,如果我缓存视图,为什么他们都不参考最老的?
如果您想了解ViewHolder工作原理的最佳解释,请在youtube(特别是前15分钟)中查看Romain Guy的Google I/O 2009对话。
简而言之,Adapter
用作底层数据和ViewGroup
之间的链接。它将根据需要渲染尽可能多的填充屏幕。在滚动或其他任何推动View
不在屏幕上的事件时,Adapter
将重新使用填充了正确数据的View
以在屏幕上呈现。
getView(int pos, View view, ViewGroup parent)
方法将随时使用正确的View
,无论您的布局如何。我不知道这个内部,但我确定你可以浏览任何适配器的源代码(如ArrayAdapter.java),如果你有兴趣。
ViewHolder
只是保持指向Views
的指针,由view.findViewById(int id)
获得。适配器的责任是返回与任何位置相对应的正确数据。
幻灯片11到13的Romain's presentation将使它比我能写的任何东西更清晰。
我相信列表视图下的工作是这样的(考虑到我们只有一个项目视图类型):
做一次:对于每一个项目
inflate item view from layout, cache it
重复:
ask adapter to fill the data into the view
draw the view on the screen
move to next item
所以你有从xml布局夸大的视图,可以重复使用绘制多个列表项。 ViewHolder通过保存getViewById查找来加快速度。
这样只有一个视图,它如何将数据填充到不同的位置(例如TextView)? – 2011-05-12 08:13:59
@Lai Yu-Hsuan它需要第一个项目,将所有数据从适配器填充到textFields等等,绘制这个视图,移动到下一个项目,重复..你不必为每个项目都有单独的视图对象那 – 2011-05-12 09:12:14
哦,我明白了。所以我们重复使用这个视图:一个例子,多次绘制,righr?所以我想我不能在视图层次结构中访问这些视图? – 2011-05-12 09:43:21
对不起,但denis的答案可能是错的。 实际上,视图实例(和ViewHolders)为,与您的屏幕可显示一样多。
如果你的屏幕看起来像:
[list view]
the first item
the second item
the third item
the fourth item
你有意见4个实例。如果您滚动屏幕,则第一项将消失,但会传递给getItem()作为convertView
供您创建第五项。
因此,您可以使用第一个ViewHolder中的引用。
这意味着在绘制第一个项目ListView时创建视图,而不是将其作为“convertView”传递。如果你从'getItem'返回相同的'convertView',那么你在渲染第二个项目时又会看到相同的视图.. :)不会有两个视图,对吧? – 2011-05-13 05:31:16
我认为这是......错的。至少accroding我在#android-dev上听到的。只有在视图消失后才能重用视图。因此,如果您的屏幕大于一个项目,则无法使用第一个视图来绘制第二个项目。如果屏幕上有N个项目,则有N个视图实例。 – 2011-05-13 05:45:59
查看源代码后,我必须同意该算法不像我想象的那么简单和直接。它涉及一些意见,其中一些是可重用的,有些则不是。将不得不挖掘更多的来源,以了解发生了什么.. – 2011-05-13 06:03:02
感谢指出这样一个信息丰富和真棒视频。 – 2011-06-24 20:07:59