我的应用程序中有一个ListView,用于显示包含两种类型项目的列表。它当前实现的方式是我为每个项类型提供两种不同的XML布局,我的适配器正确报告类型,在getView()方法中,我根据指定位置的类型对适当的XML进行扩充。
问题在于,在绝大多数情况下,项目列表的结构是大多数类型1项目在开头,大多数类型2项目最终,所以通常一开始你看到大多数是1型项目,你向下滚动,在某些时候你开始看到2型项目,它们会一直持续到列表的末尾。
当我滚动直到我击中那个中点时,一切正常。在这一点上,所有对getView()的调用都将作为convertView参数传递。这显然是有道理的。问题是,似乎ListView在回收器中存储了所有以前的类型1视图,只要我继续向下滚动,我就不会使用它们,因为从现在起大多数视图都将是类型2视图。
视图非常复杂,在它上面有自定义背景和位图,所以我最终会在内存中找到很多我可能永远不会使用的视图。
我的问题有两个:
我应该担心吗?现在我还没有得到OOM异常,但是我会不会到达那里,或者ListView是否足够聪明,以便在资源紧张时“放开”其中一些视图?
如果我确实需要担心它,有没有办法明确告诉ListView清理它的回收器,甚至以某种方式禁用它?
一个可能的解决方案是对两个布局使用相同的XML,在那里有两个ViewGroup,只是将其中一个ViewGroup的可见性设置为GONE,但如果我从来没有看到相当复杂的视图层次结构似乎是浪费要展示它。
答案 0 :(得分:1)
在Adapter中处理两种不同类型的子视图的一个建议是使用getViewTypeCount
方法,让适配器知道您实际上使用了两种不同类型的视图。
listView维护每个视图类型的每个回收器(在您的情况下,数字将为2),因此您不必担心任何OOM异常,也不需要告诉ListView清除它的回收器。
有关详细说明, 检查:getViewTypeCount and getItemViewType methods of ArrayAdapter
实施的代码段:
public class SampleAdapter extends ArrayAdapter<String> {
...
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getItemViewType(int position) {
//the result must be in the range 0 to getViewTypeCount() - 1.
if( position < 10 )
return 0;
else
return 1;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
switch( getItemViewType(position) ){
case 0:
//do something for type1 view.
break;
case 1:
//do something for type2 view.
break;
}
return convertView;
}
}
答案 1 :(得分:1)
我应该担心吗?
不,因为用户完全能够向上滚动,从而返回到第1行。
现在我还没有得到OOM异常,但是我会不会到达那里,或者ListView足够聪明,以便在资源紧张时“放开”其中一些视图?
一旦您收到OutOfMemoryError
条消息,此ListView
就不是您的问题了。你只有那么多行View
结构,从内存消耗的角度来看,所有结构都应该非常便宜。
答案 2 :(得分:0)
只有2种视图类型时我不会太担心。
如果你想优化它,我建议不要使用非常复杂的布局,而是使用自定义View
并自己绘制Bitmap
。这是一项更复杂的任务,但在通过中点时会带来更好的用户体验。