Help us understand the problem. What is going on with this article?

VolleyのImageLoaderをListViewで使うときの注意点

More than 5 years have passed since last update.

結論

キャンセル処理はちゃんと入れよう。

Volley

Android開発で、ネットワーク通信周りの処理を簡単に実装できるすごく便利なライブラリ。JSONの取得とか、画像の非同期取得とか簡単に実装できる。

ListViewの実装パターン

ListView使う時はviewのインスタンスを再利用したり、ViewHolder使うのが定石になってます。
adapter#getView()はだいたいこんな実装

sample
private class ViewHolder {
    ImageView imageView;
    TextView textView;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;

    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.list, null);

        ImageView imageView = (ImageView)convertView.findViewById(R.id.image);
        TextView textView = (TextView)convertView.findViewById(R.id.text);

        holder = new ViewHolder();
        holder.imageView = imageView;
        holder.textView = textView;

        convertView.setTag(holder);
    } else {
        holder = (ViewHolder)convertView.getTag();
    }

    // 画像やテキストの設定

    return convertView;
}

画像をVolleyのImageLoaderを使って非同期で読み込む

VolleyのImageLoaderを使うと簡単に画像を非同期で読み込むことができます。
使い方はネットワーク通信用ライブラリVolleyを使いこなすに詳しく乗っているので見てください。

惜しい実装パターン

画像読み込みの処理だけ加えた実装

sample
private ImageLoader mImageLoader;

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;

    if (convertView == null) {
        // 上と一緒
    } else {
        holder = (ViewHolder)convertView.getTag();
    }

    String imageUrl = "<画像のurl>";
    ImageListener listener = ImageLoader.getImageListener(holder.imageView, 
            R.drawable.progress, R.drawable.error);
    mImageLoader.get(imageUrl, listener);

    return convertView;
}

これで、ImageViewに非同期で読み込んだ画像がセットされます。

ただ、これだけだとちょっと問題があって、表示された順に画像読み込みのリクエストが投げられるので、ListViewを高速にスクロールすると、どんどんリクエストが溜まっていきます。
リクエストは順番に処理されるので、通りすぎて表示する必要のなくなった画像のリクエストが終わるまで、次のリクエストが処理されなくなり、ロード時間が長くなります。
また、viewを再利用するようになっているので、違うポジションの画像が表示されたりする問題も発生します。

そこで次のように、適切にリクエストのキャンセル処理を入れてあげます。

キャンセル処理をいれたパターン

sample
private ImageLoader mImageLoader;

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;

    if (convertView == null) {
        // 上と一緒
    } else {
        holder = (ViewHolder)convertView.getTag();
    }

    // リクエストのキャンセル処理
    ImageContainer imageContainer = (ImageContainer)holder.imageView.getTag();
    if (imageContainer != null) {
        imageContainer.cancelRequest();
    }

    String imageUrl = "<画像のurl>";
    ImageListener listener = ImageLoader.getImageListener(holder.imageView, 
            R.drawable.progress, R.drawable.error);
    holder.imageView.setTag(mImageLoader.get(imageUrl, listener));

    return convertView;
}

ImageLoader#get()の返り値のImageContainerはリクエストを管理しているので、このインスタンスをImageViewのタグに設定して保持しておきます。

Viewの再利用時にImageViewからImageContainerのインスタンスを取得し、リクエストのキャンセルを行っています。

これで、必要のなくなったリクエストはキャンセルされて、無駄な処理を省くことができます。

gari_jp
Androidアプリ作ってます。 通信量モニター(http://goo.gl/dWA1WU )の中の人。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした