Picasso — How to Deal with Null/Empty Values (in ListViews)

In the previous blog posts, we've looked at loading images into ListViews with Picasso and how to use placeholders. You've learned that Picasso expects non-null and valid URLs. In this blog post, we'll show you how to deal with null values, especially in ListViews, where the re-usage of views can lead to subtle display bugs.

Picasso Series Overview

How to Deal with Null/Empty Values (in ListViews)

This blog post is for two audiences. First, the developers who ran into IllegalArgumentException: Path must not be empty issues. Second, developers who want to make sure that their apps behave correctly when using incomplete image sets in ListViews.

We'll demonstrate everything in the SimpleImageListAdapter class we've shown you in the ListView blog post of this Picasso series. We'll continue to use the exact same class and method setup:

public class SimpleImageListAdapter extends ArrayAdapter {  
    private Context context;
    private LayoutInflater inflater;

    private String[] imageUrls;

    public SimpleImageListAdapter(Context context, String[] imageUrls) {
        super(context, R.layout.listview_item_image, imageUrls);

        this.context = context;
        this.imageUrls = imageUrls;

        inflater = LayoutInflater.from(context);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // changed, see next code blog
    }
}

Now, let's look at the interesting part of the getView() method. First of all, you've to catch the case that the passed image URL is either null or an empty string. Luckily, Android has a helper method TextUtils.isEmpty().

If the passed image URL is empty, you've to make a decision. Do you want to leave the ImageView empty or display a placeholder?

Option 1: Leave ImageView Empty

If you want to leave the ImageView empty, you need to cancel the Picasso request with cancelRequest(). This makes sure that there is no open request going on for that particular ImageView. This might happen if the user is scrolling very fast through a ListView and the ImageView gets re-used by the system. This avoids the situation where an incorrect image from a previous ListView item gets displayed.

The second part is to reset the ImageView. You won't need Picasso to empty the ImageView. You can just call imageView.setImageDrawable(null);. However, you'll need to make sure this won't look weird in your UI, since your ImageView might still occupy the space in the UI.

Option 2: Display Placeholder

The other option is to use a placeholder instead of an empty ImageView. Which option fits better depends on your personal opinion and on the use case.

If you decide for a placeholder, you should utilize Picasso for it. You can use the regular .load().into(imageView) Picasso call chain to load a placeholder. If you do use Picasso for it, you won't need to call cancelRequest(), because Picasso does it automatically once a request for an image for this particular ImageView is coming in.

Example for the getView() Method

Let's put it all together and take a look at the entire code at our new getView() method:

@Override
public View getView(int position, View convertView, ViewGroup parent) {  
    if (null == convertView) {
        convertView = inflater.inflate(R.layout.listview_item_image, parent, false);
    }

    ImageView imageView = (ImageView) convertView;

    if (TextUtils.isEmpty(imageUrls[position])) {
        // option 1: cancel Picasso request and clear ImageView
        Picasso
                .with(context)
                .cancelRequest(imageView);

        imageView.setImageDrawable(null);

        // option 2: load placeholder with Picasso
        /*
        Picasso
                .with(context)
                .load(R.drawable.floorplan)
                .into(imageView);
        */
    }
    else {
        Picasso
                .with(context)
                .load(imageUrls[position])
                .fit() // will explain later
                .into(imageView);
    }

    return convertView;
}

We've changed the getView() method to catch the case of null and empty image URLs. Currently, we activated the empty-the-imageview-option.

Overall, this should give you enough information to deal with empty values in image ListViews. If you've any questions, let us know in the comments!

Explore the Library

Find interesting tutorials and solutions for your problems.