Thomas
Thomas

Reputation: 53

Android ListView performance

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

Answers (2)

ataulm
ataulm

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

Yash Sampat
Yash Sampat

Reputation: 30601

The root of the problem seems to be that you are adding Views 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 Views 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

Related Questions