Android 列表视图性能
Android ListView performance
在我们的 Android 应用程序中,我们有一个 ListView,其中包含不同用户之间的活动聊天会话。用户可以拥有多少个活动聊天会话没有真正的限制,因此显然这个 ListView 包含的项目数量也没有限制。
每个 ListView 项目包括:
- 1x 膨胀视图持有多张图片
- 1x ImageView
- 1x 字符串
在加载时间、外观和构图方面,一切都按照我们想要的方式进行。虽然 ListView 包含以下 20 个项目,但一切正常。一旦 ListView 开始包含超过 20 个项目,对于添加的每个项目,性能逐渐变得越来越难以忍受。
我一直在做一些试错测试,试图禁用项目结构的每个元素和组件,我发现只要我们有 any 项目中的图像类型。因此,无论哪种,当 ListView 包含超过 20 个项目时,任何图像都会导致性能下降。我该如何优化这个?我已经从我们的适配器附加了 getView + 我们添加照片的方法。
感谢任何和所有帮助 and/or 的建议:)
从我们的适配器获取视图:
public View getView(int position, View convertView, ViewGroup parent) {
System.out.println("getview:"+position+" "+convertView);
ViewHolder viewHolder;
Match match = matches.get(position);
if(convertView==null){
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.matches_list_item, parent, false);
viewHolder = initViewHolder(convertView, match);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
addGroupPhoto(imageSize, match, viewHolder, false);
if (match.matchedGroup != null) {
viewHolder.names.setText(match.matchedGroup.getMembersNames());
viewHolder.matchedText.setText(match.latestMessage.value == null ?
String.format(mContext.getString(R.string.matched_on), getFormatedMatchDate(match.matchedOn)) : match.latestMessage.value);
}
return convertView;
}
从我们的适配器添加群组照片
private void addGroupPhoto(int imageSize, Match match, ViewHolder viewHolder, boolean isSelected) {
if (viewHolder.groupPhoto.findViewById(R.id.unseen_messages) != null) {
viewHolder.groupPhoto.removeView(viewHolder.groupPhoto.findViewById(R.id.unseen_messages));
}
if (match.matchedGroup != null) {
RelativeLayout lay = Utilities.createGroupImagePhoto(mContext, imageSize, imageSize, match.matchedGroup.members, Utilities.GROUP_PHOTO_MODE_GROUP_WITHOUT_NAMES);
((RelativeLayout.LayoutParams)lay.getLayoutParams()).addRule(RelativeLayout.CENTER_VERTICAL);
((RelativeLayout.LayoutParams)lay.getLayoutParams()).addRule(RelativeLayout.ALIGN_LEFT);
((RelativeLayout.LayoutParams)lay.getLayoutParams()).setMargins(smallMargin, 0, 0, 0);
viewHolder.groupPhoto.addView(lay);
lay.invalidate();
}
ImageView crop = new ImageView(mContext);
crop.setBackgroundResource(getCropImageDrawable(isSelected));
crop.setLayoutParams(new RelativeLayout.LayoutParams(imageSize,imageSize));
((RelativeLayout.LayoutParams)crop.getLayoutParams()).addRule(RelativeLayout.CENTER_VERTICAL);
((RelativeLayout.LayoutParams)crop.getLayoutParams()).addRule(RelativeLayout.ALIGN_LEFT);
((RelativeLayout.LayoutParams)crop.getLayoutParams()).setMargins(smallMargin, 0, 0, 0);
int marginForMessage = 0;
viewHolder.groupPhoto.addView(crop);
if (!match.seen | match.newMessages > 0) {
addMessages(match.newMessages, marginForMessage, viewHolder);
}
}
编辑:这是由以编程方式添加图像引起的。在 XML 文件中添加图像及其不同属性后,无需以编程方式添加它们并声明它们的参数,一切都运行顺利。
问题的根源似乎是您在 Adapter
中添加 View
并以编程方式设置它们的 LayoutParams
。这本质上 "heavier" 比 XML 中的设置要好,并且在低端和中端设备上会变得更加明显。
除非您有令人信服的理由以这种方式添加 View
,否则您不应该这样做。 Picasso
这里帮不了你。
注意:我注意到的一件小事是你没有打电话给
convertView.setTag(holder);
在您的 getView()
方法中。这种遗漏也可能是性能问题的根源。
另一个考虑因素是,在 addGroupPhoto()
中,每个列表项至少多 findViewById()
。
ViewHolder 模式的唯一 目的是缓存对视图的引用,即仅在您首次设置 ViewHolder 时调用 findViewById
。
在我们的 Android 应用程序中,我们有一个 ListView,其中包含不同用户之间的活动聊天会话。用户可以拥有多少个活动聊天会话没有真正的限制,因此显然这个 ListView 包含的项目数量也没有限制。
每个 ListView 项目包括:
- 1x 膨胀视图持有多张图片
- 1x ImageView
- 1x 字符串
在加载时间、外观和构图方面,一切都按照我们想要的方式进行。虽然 ListView 包含以下 20 个项目,但一切正常。一旦 ListView 开始包含超过 20 个项目,对于添加的每个项目,性能逐渐变得越来越难以忍受。
我一直在做一些试错测试,试图禁用项目结构的每个元素和组件,我发现只要我们有 any 项目中的图像类型。因此,无论哪种,当 ListView 包含超过 20 个项目时,任何图像都会导致性能下降。我该如何优化这个?我已经从我们的适配器附加了 getView + 我们添加照片的方法。
感谢任何和所有帮助 and/or 的建议:)
从我们的适配器获取视图:
public View getView(int position, View convertView, ViewGroup parent) {
System.out.println("getview:"+position+" "+convertView);
ViewHolder viewHolder;
Match match = matches.get(position);
if(convertView==null){
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.matches_list_item, parent, false);
viewHolder = initViewHolder(convertView, match);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
addGroupPhoto(imageSize, match, viewHolder, false);
if (match.matchedGroup != null) {
viewHolder.names.setText(match.matchedGroup.getMembersNames());
viewHolder.matchedText.setText(match.latestMessage.value == null ?
String.format(mContext.getString(R.string.matched_on), getFormatedMatchDate(match.matchedOn)) : match.latestMessage.value);
}
return convertView;
}
从我们的适配器添加群组照片
private void addGroupPhoto(int imageSize, Match match, ViewHolder viewHolder, boolean isSelected) {
if (viewHolder.groupPhoto.findViewById(R.id.unseen_messages) != null) {
viewHolder.groupPhoto.removeView(viewHolder.groupPhoto.findViewById(R.id.unseen_messages));
}
if (match.matchedGroup != null) {
RelativeLayout lay = Utilities.createGroupImagePhoto(mContext, imageSize, imageSize, match.matchedGroup.members, Utilities.GROUP_PHOTO_MODE_GROUP_WITHOUT_NAMES);
((RelativeLayout.LayoutParams)lay.getLayoutParams()).addRule(RelativeLayout.CENTER_VERTICAL);
((RelativeLayout.LayoutParams)lay.getLayoutParams()).addRule(RelativeLayout.ALIGN_LEFT);
((RelativeLayout.LayoutParams)lay.getLayoutParams()).setMargins(smallMargin, 0, 0, 0);
viewHolder.groupPhoto.addView(lay);
lay.invalidate();
}
ImageView crop = new ImageView(mContext);
crop.setBackgroundResource(getCropImageDrawable(isSelected));
crop.setLayoutParams(new RelativeLayout.LayoutParams(imageSize,imageSize));
((RelativeLayout.LayoutParams)crop.getLayoutParams()).addRule(RelativeLayout.CENTER_VERTICAL);
((RelativeLayout.LayoutParams)crop.getLayoutParams()).addRule(RelativeLayout.ALIGN_LEFT);
((RelativeLayout.LayoutParams)crop.getLayoutParams()).setMargins(smallMargin, 0, 0, 0);
int marginForMessage = 0;
viewHolder.groupPhoto.addView(crop);
if (!match.seen | match.newMessages > 0) {
addMessages(match.newMessages, marginForMessage, viewHolder);
}
}
编辑:这是由以编程方式添加图像引起的。在 XML 文件中添加图像及其不同属性后,无需以编程方式添加它们并声明它们的参数,一切都运行顺利。
问题的根源似乎是您在 Adapter
中添加 View
并以编程方式设置它们的 LayoutParams
。这本质上 "heavier" 比 XML 中的设置要好,并且在低端和中端设备上会变得更加明显。
除非您有令人信服的理由以这种方式添加 View
,否则您不应该这样做。 Picasso
这里帮不了你。
注意:我注意到的一件小事是你没有打电话给
convertView.setTag(holder);
在您的 getView()
方法中。这种遗漏也可能是性能问题的根源。
另一个考虑因素是,在 addGroupPhoto()
中,每个列表项至少多 findViewById()
。
ViewHolder 模式的唯一 目的是缓存对视图的引用,即仅在您首次设置 ViewHolder 时调用 findViewById
。