読者です 読者をやめる 読者になる 読者になる

ひだまりソケットは壊れない

ソフトウェア開発に関する話を書きます。 最近は主に Android アプリ、Windows アプリ (UWP アプリ)、Java 関係です。

まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。

Volley 基礎 (Android アプリ用ネットワークライブラリ)

Android アプリ

本記事では、Volley の基礎部分 (RequestQueueRequest) について述べる。

Volley について

こないだの Google IO で発表された Google 製の Android アプリ用のネットワークライブラリ。 Activity に表示する情報を取得するための HTTP リクエスト *1 を処理するのに向いているようである。

この記事を最初に公開した時点ではあんまりちゃんとしたドキュメントはなかったが、現在では Android Developers にドキュメントがある。

この記事は、上のドキュメントがなかった時代にソースコードを読んで得た知識などを書いたものである。

Volley を使う準備

現在のところ jar で配布されたりはしてないので、ソースコードを git clone してきて自分で jar を作るなりソースコードをクラスパスに含めて扱うなりする必要がある。 個人的には jar を作るよりもソースコードを直接使う方がオススメ (ちょっと書きかえて試してみたりすることがやりやすいので)。

RequestQueueRequest

Volley の中で最も重要なクラスはおそらく RequestQueueRequest だと思われる。

Request (のサブクラス) をインスタンス化するときにリクエストの情報とレスポンスの扱い方を与えておいて、そのインスタンスRequestQueue#add(Request) メソッド呼び出しで渡してやるだけで HTTP リクエストがなされる。 ((下の例では JsonArrayRequest コンストラクタの引数に無名内部クラスをインスタンス化して渡すことでコールバックを設定しているが、実際に記述するときはもうちょっとまともな書き方をした方がいいだろう。))

// 必要な import 文
import com.android.volley.toolbox.Volley;

// 例えば Activity の onStart メソッドで RequestQueue のインスタンスを取得 or start
// mRequestQueue は RequestQueue 型のインスタンス変数
if (mRequestQueue == null) {
    mRequestQueue = Volley.newRequestQueue(this);
} else {
    mRequestQueue.start();
}
// 必要な import 文
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonArrayRequest;
import org.json.JSONArray;

// リクエストを投げる
JsonArrayRequest req = new JsonArrayRequest("http://example.com/hoge/fuga/test.json",
            new Response.Listener<JSONArray>() {
                @Override public void onResponse(JSONArray response) {
                    // レスポンス受け取り時の処理...
                }
            },
            new Response.ErrorListener() {
                @Override public void onErrorResponse(VolleyError error) {
                    // エラー時の処理...
                }
            });
mRequestQueue.add(req);

Request のサブクラス

Request は抽象クラスなので、実際に使うときは Volley に含まれているサブクラスを使うか、自分でサブクラスを定義してやる必要がある。

Volley には次のような Request のサブクラスが含まれている。

  • StringRequest クラス
  • ImageRequest クラス
  • JsonRequest クラス (抽象クラス)
  • JsonArrayRequest クラス
  • JsonObjectRequest クラス
  • ClearCacheRequest クラス

どういう使い方をするのかはソースコードを読めばすぐにわかるはず。

RequestQueueインスタンス

RequestQueueコンストラクタとして次の 3 つが存在する。

  • public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery)
  • public RequestQueue(Cache cache, Network network, int threadPoolSize)
  • public RequestQueue(Cache cache, Network network)

詳細は後述するが、CacheNetwork の実装をオブジェクトとして与えられるようになっている。

また、デフォルト実装を持つ RequestQueue インスタンスを返す Volley.newRequestQueue(Context) メソッドもある。 RequestQueueコンストラクタを使用する場合も Volley.newRequestQueue(Context) メソッドの実装を参考にするとよいだろう。 Volley.newRequestQueue(Context) メソッドで生成された RequestQueue は既に動いている状態 ((start メソッドが呼ばれた後の状態。)) になっている点には注意が必要である。

RequestQueue#start() メソッドRequestQueue#stop() メソッド

RequestQueue 内部のスレッドを起動したり終了したりするためのメソッドとして次の 2 つがある。

ActivityonStop メソッド ((onPause の方がいいのかな?)) で stop し、onStart メソッドstart するなど、適切な場所でこれらのメソッドを呼び出すこと。

リクエストのキャンセル

Request#cancel() メソッドというものがあり、リクエストのキャンセルができるようになっている。

実際に何が行われているかというと、Request#cancel() メソッドが呼ばれると Request オブジェクトにキャンセルフラグが立つだけである。 そして、キューから取り出された Request オブジェクトにキャンセルフラグが立っている場合は、ネットワーク通信を行わない、という程度の処理が入るだけっぽい。 ネットワーク通信が開始された後だと Request#cancel() メソッドの呼び出しはあまり意味がないように思える。

RequestQueue#cancelAll メソッドというのもあり、こちらは RequestQueue が保持している Request のうち、条件に合うものすべてに対して cancel メソッド呼び出しを行うというものである。

無駄なリクエストを行わないように、必要に応じてリクエストのキャンセルをすること。

RequestQueue の実装について

RequestQueue の内部の処理がどのように行われているかというと、以下のような感じだった。 ざっくりした図だし微妙にわかりにくいけど。

Request オブジェクトを格納するキューが 2 本あって、それぞれキャッシュ内に存在している場合用とネットワーク通信で取得する用になっている。 動いている RequestQueue が行う処理は基本的に次のことだけである *2

  1. RequestQueueRequest を受け取った後、最初に Cache にリクエスト対象が存在するかどうか確認する
    1. リクエストがキャッシュされるべきものでないならネットワークから取得する用のキューに Request を入れる
    2. さもなければキャッシュ用のキューに Request を入れる

あとは後ろで動いている別のスレッドがよしなに処理を行ってくれて、最終的に Requestメソッドが呼ばれてレスポンスが渡される。

f:id:nobuoka:20130609001808p:plain

使う側が実装を定義できる部分

上の図のピンク色の背景色の部分はインターフェイス (または抽象クラス) であり、RequestQueue と実装が結び付いているわけではない箇所である。 それらについては、RequestQueueインスタンス化時にオブジェクトを渡してやることで、RequestQueue 利用者側が実装を定義できる。

また、これらのインターフェイスを実装したクラスが Volley には入っているので、そういったクラスを使用することもできる。

例えば、Cache インターフェイスを実装するクラスとしては DiskBasedCacheNoCache が Volley に含まれている。 独自にキャッシュ方式を定義したい場合などは自分でクラスを定義して RequestQueueインスタンス化時にそのクラスのインスタンスを渡してやればよい。

まとめ

  • RequestQueue#add メソッド呼び出し時に Request のサブクラスのインスタンスを渡すことでリクエストが処理される (バックグラウンドスレッドで)
  • RequestQueue は内部でキャッシュを使用する
    • キャッシュの実装はライブラリ利用者が定義できる
    • デフォルト実装としてファイルシステムを使ったキャッシュなどが Volley に含まれている
  • ネットワーク通信の実装もライブラリ利用者が定義できる
    • デフォルト実装が Volley に含まれているので、特にカスタマイズが必要でなければそれを使用すればよい
  • 適切な場所でバックグラウンドスレッドの開始と停止を行うこと
    • ActivityonStart メソッドRequestQueuestart (一例)
    • ActivityonStop メソッドRequestQueuestop (一例)
  • 不要になった Request に対しては cancel メソッドを呼び出すこと

携帯OS教科書 Androidアプリケーション技術者ベーシック

携帯OS教科書 Androidアプリケーション技術者ベーシック

*1:あまりレスポンスのサイズは大きくなく、一度に複数個のリクエストを処理したいというような状況。

*2:開始時の処理や停止時の処理はいろいろあるけど。