話題の記事

Android Tips #51 ネットワーク通信・キャッシュ処理をより速く、簡単に実装できるライブラリ “Volley” を使ってみた

2013.05.23

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Volley とは

先日開催された Google I/O 2013 で Volley というネットワーク処理を高速化するライブラリが発表・公開されました。Volley を使うとよくあるネットワーク通信処理やキャッシュ処理を今までより簡単に実装することができます。物凄く魅力的ですね!以下のような機能があるようです。

  • JSON や画像ファイルなどのダウンロード非同期処理の簡素化
  • リクエストのスケジューリング
  • リクエストの優先順位付け
  • メモリキャッシュ・ディスクキャッシュ
  • 強力で簡単なリクエストキャンセル
  • Activity が存在しないときの自動キャンセル

ということで Volley をアプリに入れて使うまで試してみたいとおもいます。またセッションの内容は以下の記事に分かりやすくまとまっているので参考にしてください。ちなみに AndroidManifest.xmlandroid:minSdkVersion="8" とあったので Android 2.2 (APIレベル8) から使えるようです。

Google I/O 2013 - Android : Volley: Easy, Fast Networking for Android | Y.A.M の 雑記帳

Volley をプロジェクトにインポートする

まず Git リポジトリを clone します。

git clone https://android.googlesource.com/platform/frameworks/volley

あとは clone してきた volley プロジェクトを Android プロジェクトとしてインポートします。筆者の環境では Is Library にチェックが付いていなかったので、Android アプリプロジェクトにインポートする前にライブラリが有効になっているか確認しておきましょう。あとは Android アプリプロジェクトを作成してライブラリをインポートして完了です!

volley01

Eclipse プロジェクトなので Android Studio で使いたい場合は Eclipse で Gradle ファイルを作ってからインポートしてください。

Volley を使ってみる

それでは早速実装してみましょう。

JSON データを取得する

まずはじめに JSON データを取得する処理です。以下のように書きます。

private RequestQueue mQueue;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mQueue = Volley.newRequestQueue(getApplicationContext());
    requestVolley();
}

private void requestVolley() {
    // Volley でリクエスト
    String url = "http://www.google.com/uds/GnewsSearch?q=Obama&v=1.0";
    mQueue.add(new JsonObjectRequest(Method.GET, url, null,
            new Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject response) {
                    Log.d(TAG, "response : " + response.toString());
                }
            }, null));
    mQueue.start();
}

基本的に RequestQueue クラスがよく使うクラスになります。このクラスは Volley.newRequestQueue() メソッドで取得し、シングルトンで扱うのが基本です。RequestQueue.add() メソッドでリクエストを追加します。第一引数に HTTP メソッド名、第二引数に URL、第三引数はリクエストパラメータ、第四引数は Listener<JSONObject>、第五引数は Listener<JSONObject> を渡します。今回は第三、五引数が不要だったので null にしています。AsyncTaskLoader とか使わなくていいので楽に実装できますね!
DefaultHttpClient を使った場合と速度を比較してみました。

volley02

あれ、 Volley のほうがちょっと遅いですね・・・w
他のライブラリを使った時より速い、という話なのか、実装の仕方で速くなるのか。。見なかったことにしましょうw

GridView で画像アイテムをリクエストしつつメモリキャッシュする

次に画像データのリクエスト&キャッシュ化です。GridViewArrayAdapter は以前までと変わらない形で実装することとして、肝心なのは ArrayAdapter.getView() のときにリクエストする処理です。以下のように実装します。

package jp.classmethod.android.sample.volley;

import java.util.List;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;

import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.ImageLoader.ImageListener;
import com.android.volley.toolbox.Volley;

public class ImageAdapter extends ArrayAdapter<String> {
    
    private RequestQueue mQueue;
    private ImageLoader mImageLoader;

    public ImageAdapter(Context context, List<String> objects) {
        super(context, 0, objects);
        mQueue = Volley.newRequestQueue(getContext());
        mImageLoader = new ImageLoader(mQueue, new BitmapCache());
    }
    
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        String url = getItem(position);
        ImageView imageView;
        if (convertView == null) {
            imageView = new ImageView(getContext());
        } else {
            imageView = (ImageView) convertView;
        }
        // 画像取得処理
        ImageListener listener = ImageLoader.getImageListener(imageView, android.R.drawable.ic_menu_rotate, android.R.drawable.ic_delete);
        mImageLoader.get(url, listener);
        return imageView;
    }

}

画像を取得する処理は ImageLoader.get() メソッドです。このメソッドの引数には URL と ImageListener というインターフェースを実装したクラスのインスタンスをセットします。ImageListenerImageLoader.getImageListener() で取得できます。第一引数に取得した画像をセットする ImageView をセットし、第二引数には読込中画像の Drawable を、第三引数には読み込み失敗画像の Drawable をセットします。
RequestQueueImageLoader は使いまわせるので、コンストラクタで定義しています。ImageLoader の第二引数にセットしている BitmapCache というのは ImageCache インターフェースを実装した、画像キャッシュ処理クラスです。以下のように実装します。

package jp.classmethod.android.sample.volley;

import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

import com.android.volley.toolbox.ImageLoader.ImageCache;

public class BitmapCache implements ImageCache {
    
    private LruCache<String, Bitmap> mCache;
    
    public BitmapCache() {
        int maxSize = 10 * 1024 * 1024;
        mCache = new LruCache<String, Bitmap>(maxSize) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight();
            }
        };
    }

    @Override
    public Bitmap getBitmap(String url) {
        return mCache.get(url);
    }

    @Override
    public void putBitmap(String url, Bitmap bitmap) {
        mCache.put(url, bitmap);
    }

}

LruCache クラスの使いかたはこちらで解説しているので参考にしてください。
ちゃんと読み込みつつキャッシュすることができました!画像URLは2種類しか使っていないので、ほとんど使い回しになっているのでなんとも言えませんが。。

volley03

単一の画像をリクエストしつつメモリキャッシュする

上記ではリストアイテムの実装ですが、単一の画像をリクエスト・キャッシュしたい場合は NetworkImageView クラスを使うと実装できます。このクラスは基本的に ImageView の代わりに使います。

NetworkImageView view = (NetworkImageView) findViewById(R.id.network_image_view);
view.setImageUrl(url, new ImageLoader(mQueue, new BitmapCache()));

NetworkImageView.setImageUrl() の第二引数に ImageCache を実装したクラスが必要になるので、上記と同様実装クラスを準備しておく必要があります。かなり簡単に読み込めるのは良いですね!しかし ImageListener をセットするメソッドが見当たらなかったので ImageLoader.get() を使ったほうがいろいろカスタマイズしやすいかも知れません。

サンプルソースを公開しました

今回実装した処理を簡単に試すことができるソースコードを GitHub に公開しました! clone するだけですぐ試すことができます。

suwa-yuki/VolleySample

まとめ

これまで AsyncTaskLoader を使って実装していましたが、このクラスを直接的に使わずに実装できるようになっています。今回は軽く使っただけですが、リクエストのカスタマイズもかなり柔軟らしいです。これから Volley を使うことが標準になるんですかね。
今回公開したサンプルはすぐ使える形になっているので、まずは clone して試してみてください!

参考