Reputation: 53
In our Android application we've got a ListView filled with active chatsessions between different users. There's no real limit to how many active chatsessions a user can have, so obviously there's no limit to how many items this ListView contains either.
Each ListView item consists of:
Everything works out the way we want to in terms of loading times and in terms of looks and composition. While the ListView contains below 20-ish items, everything is ok. As soon as the ListView starts containing above those 20-ish items, the performance turns gradually more and more unbearable for each item added.
I've been doing some trial and error testing, trying to disable each element and component of the item structure, and what I've found is that the performance drop happens whenever we have any kind of image in the items. So no matter what kind, any image causes the performance to suck, when the ListView contains more than 20-ish items. How do I optimize this? I've attached the getView from our adapter + our method for adding the photos.
Any and all help and/or suggestions are appreciated :)
getView from our adapter:
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;
}
addGroupPhoto from our adapter
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);
}
}
EDIT: This was caused by programmatically adding the images. After adding the images and their different attributes inside the XML-file, instead of adding them and declaring their parameters programmatically, everything is working smoothly.
Upvotes: 1
Views: 146
Reputation: 15334
An additional consideration is that in addGroupPhoto()
you're making at least one more findViewById()
per list item.
The sole purpose of ViewHolder pattern is to cache the references to views, i.e. only call findViewById
when you're setting up your ViewHolder for the first time.
Upvotes: 1
Reputation: 30601
The root of the problem seems to be that you are adding View
s and setting their LayoutParams
programmatically in your Adapter
. This is inherently "heavier" than setting it in XML, and would become even more noticeable on low and medium-end devices.
Unless you have a compelling reason for adding View
s in this way, you shouldn't. Picasso
won't help you here.
Note: A small thing I've noticed is that you haven't called
convertView.setTag(holder);
in your getView()
method. This omission can also be a source of performance problems.
Upvotes: 1