自定义列表视图适配器 getView 方法被多次调用,并且顺序不一致
Posted
技术标签:
【中文标题】自定义列表视图适配器 getView 方法被多次调用,并且顺序不一致【英文标题】:custom listview adapter getView method being called multiple times, and in no coherent order 【发布时间】:2011-02-06 18:39:55 【问题描述】:我有一个自定义列表适配器:
class ResultsListAdapter extends ArrayAdapter<RecordItem>
在覆盖的 'getView' 方法中,我进行打印以检查位置是什么以及它是否是 convertView:
@Override
public View getView(int position, View convertView, ViewGroup parent)
System.out.println("getView " + position + " " + convertView);
这个的输出(当列表第一次显示时,还没有用户输入)
04-11 16:24:05.860: INFO/System.out(681): getView 0 null
04-11 16:24:29.020: INFO/System.out(681): getView 1 android.widget.RelativeLayout@43d415d8
04-11 16:25:48.070: INFO/System.out(681): getView 2 android.widget.RelativeLayout@43d415d8
04-11 16:25:49.110: INFO/System.out(681): getView 3 android.widget.RelativeLayout@43d415d8
04-11 16:25:49.710: INFO/System.out(681): getView 0 android.widget.RelativeLayout@43d415d8
04-11 16:25:50.251: INFO/System.out(681): getView 1 null
04-11 16:26:01.300: INFO/System.out(681): getView 2 null
04-11 16:26:02.020: INFO/System.out(681): getView 3 null
04-11 16:28:28.091: INFO/System.out(681): getView 0 null
04-11 16:37:46.180: INFO/System.out(681): getView 1 android.widget.RelativeLayout@43cff8f0
04-11 16:37:47.091: INFO/System.out(681): getView 2 android.widget.RelativeLayout@43cff8f0
04-11 16:37:47.730: INFO/System.out(681): getView 3 android.widget.RelativeLayout@43cff8f0
AFAIK,虽然我找不到明确说明,但 getView() 仅对可见行调用。由于我的应用程序以四个可见行开头,因此至少从 0-3 循环的位置编号是有意义的。但剩下的就是一团糟:
为什么每行调用 getview 三次? 当我还没有滚动时,这些 convertView 是从哪里来的?我进行了一些研究,但没有得到好的答案,但我确实注意到人们将此问题与布局问题相关联。因此,以防万一,这是包含列表的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:orientation="vertical" >
<TextView android:id="@+id/pageDetails"
android:layout_
android:layout_ />
<ListView android:id="@+id/list"
android:layout_
android:layout_
android:drawSelectorOnTop="false" />
</LinearLayout>
以及每一行的布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:padding="4dp">
<ImageView
android:id="@+id/thumb"
android:layout_
android:layout_
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginRight="8dp"
android:src="@drawable/loading" />
<TextView
android:id="@+id/price"
android:layout_
android:layout_
android:layout_toRightOf="@id/thumb"
android:layout_alignParentBottom="true"
android:singleLine="true" />
<TextView
android:id="@+id/date"
android:layout_
android:layout_
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:paddingRight="4dp"
android:singleLine="true" />
<TextView
android:id="@+id/title"
android:layout_
android:layout_
android:textSize="17dp"
android:layout_toRightOf="@id/thumb"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:paddingRight="4dp"
android:layout_alignWithParentIfMissing="true"
android:gravity="center" />
</RelativeLayout>
感谢您的宝贵时间
【问题讨论】:
【参考方案1】:“为什么每行调用 getview 三次?” 因为当您在 listview 上滚动时会调用 getView,并且更好地说是在更改列表视图的位置时调用它!
【讨论】:
好的,但是视图没有改变。活动开始时屏幕上有四个行视图,并且根本没有滚动或任何用户输入,我每行都收到三个 getView 调用... 这个答案是错误的。正确答案是使用 ** wrap_content** 会导致对 getView 的大量调用。【参考方案2】:这不是问题,绝对不能保证getView()
的调用顺序和调用次数。在您的特定情况下,通过给它一个height=wrap_content
,您正在用ListView
做最糟糕的事情。这迫使ListView
在布局时从适配器中测量几个孩子,以了解它应该有多大。这就是为ListView
提供convertViews
的原因,您甚至在滚动之前就看到传递给getView()
。
【讨论】:
我不认为这是一个很好的理由。如果您希望能够进行更改,那很好,但目前它没有回答为什么会这样做? @cdpnet 他确实说了为什么要这么做,你的ListView
的高度是wrap_content
,所以它不确定它的高度,因此它把一些孩子当作一种测试者看看适合什么。将您的 ListView
更改为 fill_parent
然后检查您的日志,呼叫应该会大大减少。
2.3 和 4.x 时代 ListView 之间的行为发生了显着变化。要点是,在设计 ListView 时,您的单元格/list_items 需要是纯视图,并且需要针对快速绘图进行优化。根据 Romain 提出的关于 ListView 的 Google I/O 演讲,可能调用 getView 只是为了优化视图渲染并丢弃结果。虽然在我看来这不像 ios UITableView 那样对开发人员友好,但它就是这样。
非常感谢!我不明白为什么 getView() 被如此频繁地调用。我将 wrap_content 切换为 fill_parent,现在我的应用又快了 :)
将ListViews设置为layout_height=wrap_content时应该有警告,因为它会导致很多性能问题。【参考方案3】:
尝试在列表视图的layout_height
属性上使用match_parent
。它将防止getView()
被如此频繁地调用。
【讨论】:
请注意,Fred T 指定了 LIST VIEW 的 layout_height...而不是行,这是我反复尝试的 请注意,对于 API 级别 8 及更高级别,fill_parent
应替换为 match_parent
。
我认为 getView() 方法会调用多次,通过将宽度和高度设置为 ListView 的 match_parent 只能解决性能问题。【参考方案4】:
我也有同样的问题。如果我将高度设置为 fill_parent,那么我会“通常”每行获得 2 个调用。但是,如果我将 ListView 的高度设置为精确值,比如说 300dp,那么我每行都会得到一个 GetView 调用。
所以,在我看来,唯一的方法是首先确定屏幕的高度,然后以编程方式将 listview 的高度设置为该值。我不喜欢它。希望有更好的办法。
【讨论】:
谢谢。这很有趣——这个问题已经沉睡了几个月,只是在过去的几周里出现了一些 cmets。我不再做这个项目,但因为我有时间我会尝试一下,然后回到这里确认。再次感谢。 这里也一样,我每行接到两个电话。第 0,1,2,3 行,然后 100 毫秒后又是 0,1,2,3 行 - 在收集有关所见行的统计信息时,这是一件很痛苦的事【参考方案5】:我无法回答您的“为什么”问题,但我绝对有办法解决烦人的“ListView 项目重复”问题(如果您的收藏中的项目更多比屏幕高度)。
正如上面许多人提到的,将 ListVew 标记的 android:layout_height 属性保留为 fill_parent。
关于 getView() 函数,解决方案是使用一个名为 ViewHolder 的静态类。查看this 示例。它成功地完成了在 Array 或 ArrayCollection 中添加所有项目的任务。
希望对朋友有帮助!!
最好的问候, 悉达特
【讨论】:
在 android 的早期版本(ICS 之前)中使用 ViewHolder 模式时要谨慎,因为它可能会导致 MemoryLeak 异常。随意在 ICS+ 版本中使用它。 @Siddhant 谢谢我花了一天的时间来找出在我的GridView
中重复图像并更改android:layout_height
和android:layout_width
的原因对我不起作用。但是为我使用ViewHolder
fixed 重复图像,我完成了本教程android-vogue.blogspot.com/2011/06/…【参考方案6】:
当我将 layout_width 和 layout_height 都更改为 match_parent 时,我解决了这个问题(仅更改 layout_height 没有帮助)。
有用的提示注意是否有嵌套项。您必须将“最高”更改为 match_parent。希望它可以帮助某人。
【讨论】:
一个单词好友“真棒”,但不知道为什么 wrap_content 会产生问题。这解决了我的问题。 @AndroidKiller 当你使用wrap_content
,然后ListView
不知道有多少列表项成为List 的内容,这就是ListView
尝试创建尽可能多的行的原因适合显示,当你使用fill_parent
或match_parent
时,ListView
认为,好吧,我的身高是x
,我需要n
显示的行数。
非常感谢!由于多次调用,图像会随机变化......现在从一开始就可以了。【参考方案7】:
问题:为什么 Adapter 会多次调用 getView()? Ans:当 Listview 在滚动时呈现是用下一个即将到来的视图刷新它的视图,对于 哪个适配器需要通过调用 getView() 来获取视图。
问题:如果列表视图的宽度和高度设置为fill_parent,为什么它的调用更少? Ans: 因为充气机对于列表的屏幕区域具有固定大小,所以它计算一次 将视图渲染到屏幕上。
希望它能解决您的问题。
【讨论】:
很好的解释。但 match_parent 可能是更好的选择。 是的@JoeBlow,建议从 API 2.4/3.0 开始使用 match_parent 而不是 fill_parent【参考方案8】:我在 AutoCompleteTextView 中的下拉菜单中遇到了同样的问题。我与这个问题斗争了两天,直到我到达这里,你告诉我解决方案。
如果我写 dropDownHeight="match_parent" 问题就解决了。现在问题与 UI 有关(当您有一个项目时,下拉菜单太大)但多次调用的问题(更重要)已得到修复。
谢谢!!
【讨论】:
【参考方案9】:对于所有仍然(在将ListView
的height
设置为match_parent
之后)卡住的人(就像我一样):
您还必须将父布局的height
设置为match_parent
。
请参见下面的示例。 LinearLayout
是这里的父级:
<LinearLayout
android:layout_
android:layout_
android:orientation="vertical">
<TextView
android:layout_
android:layout_
android:text="@string/something" />
<ListView
android:id="@+id/friendsList"
android:layout_
android:layout_ />
</LinearLayout>
【讨论】:
【参考方案10】:这可能来晚了,但如果您使用layout_weight
,请记住始终设置layout_width="0dp"
【讨论】:
【参考方案11】:我做了这个解决方案,也许不是最好的,但确实有效......
//initialize control string
private String control_input = " ";
那么 =
@Override
public View getView(int position, View convertView, ViewGroup parent)
View gridview = convertView;
// change input_array for the array you use
if (!control_input.equals(input_array[position]))
control_input = input_array[position];
//do your magic
return gridview;
希望对你有帮助!
【讨论】:
以上是关于自定义列表视图适配器 getView 方法被多次调用,并且顺序不一致的主要内容,如果未能解决你的问题,请参考以下文章
listview 项目未在自定义适配器的 getview 方法中显示分配的值