Volleyは、効率的なHTTPリクエスト実行と画像読み込みのためにGoogleが開発したAndroid用ネットワークライブラリです。ライブラリは自動的にスレッドプールを管理し、レスポンスをキャッシュし、リクエストに優先順位を付けます。Google, 2025によると、Volleyは複雑な依存関係を設定せずに迅速な開始が必要なプロジェクトで人気のある選択肢であり続けています。
重要なポイント
Volleyは、GoogleがI/O 2013カンファレンスで発表したAndroidアプリケーション向けネットワーク通信用ライブラリです。Volleyという名前は「斉射」を意味し — インターフェースの応答速度が重要なUI指向アプリケーションに特徴的な、複数の並行高速リクエストを実行するために設計されています。
VolleyはHttpURLConnectionとAsyncTaskの問題(手動スレッド管理、キャッシュの欠如、リクエスト優先順位付けの複雑さ、冗長なコード)の解決策として作成されました。GoogleはVolleyを「fire-and-forget」タイプの操作 — 結果が即座にインターフェースに表示される小さなリクエスト — のためのライブラリとして位置づけました。
Volleyのアーキテクチャは3つの主要コンポーネントで構成されています:RequestQueue(キューマネージャー)、CacheDispatcher(キャッシュされたレスポンス用スレッド)、NetworkDispatcher(ネットワークスレッド)。このアーキテクチャは自動的にリクエストを分散します:最初にキャッシュがチェックされ、キャッシュがない場合にのみネットワークリクエストが実行されます。これにより、繰り返しデータのレイテンシが50〜80%削減されます。
RequestQueueはVolleyの中心的なクラスです。Request<T>オブジェクトが追加され、キューは自動的にそれらを2種類のスレッドに分散します:CacheDispatcher(1つのスレッド、キャッシュ可能なリクエストを処理)とNetworkDispatcher(複数のスレッド、実際のHTTPリクエストを実行)。デフォルトでは、Volleyは4つのネットワークスレッドを作成します。
リクエストが追加されると、RequestQueueはキャッシュから提供できるかどうかを確認します。キャッシュに最新のレスポンスがある場合、CacheDispatcherはネットワークリクエストなしで即座にそれを返します。キャッシュが古いか存在しない場合、リクエストはNetworkDispatcherに渡されます。リクエストの優先度(low、normal、high、immediate)はキュー内の処理順序を決定します — high優先度のリクエストはnormalより先に処理されます。
リクエスト実行後、結果はHandlerを介してメインスレッド(UIスレッド)に配信されます。VolleyはonResponse()とonErrorResponse()のコールバックを自動的にメインスレッドに切り替えるため、追加のスレッド切り替えなしでコールバック内で直接インターフェースを更新できます。これによりコードが簡素化され、スレッド関連のエラーがすべて排除されます。
Volleyのもう一つの特徴は自動リクエスト重複排除です。同じURLとパラメータを持つ2つの同一のGETリクエストがキューに追加された場合、Volleyはそのうちの1つだけを実行し、両方のコールバックに同じレスポンスを返します。これは、複数のコンポーネントが独立して同じデータをリクエストする画面(例えば、ヘッダーと設定フラグメントの両方で同時に必要なユーザープロファイル)で特に便利です。
各リクエストは一連のステップを経ます:Requestの作成、RequestQueueへの追加、キャッシュの確認(CacheDispatcher)、HTTPリクエストの実行(NetworkDispatcher)、Response.Listenerによるレスポンスの解析、UIスレッドへの結果配信。リクエストがキャンセルされると(cancel)、RequestQueueはキューから削除し、コールバックの呼び出しを防ぎます。
VolleyはRetryPolicyもサポートしており、障害発生時の再試行回数を決定します。DefaultRetryPolicyはデフォルトで2.5秒のタイムアウトで1回の再試行を行います。不安定な接続の場合、再試行回数は3回、タイムアウトは10秒に増やすことができます。カスタムRetryPolicyは、getCurrentTimeout、getCurrentRetryCount、retryメソッドを持つRetryPolicyインターフェースを介して実装されます。
Volleyは一般的なデータ形式に対応した既製のリクエストタイプを提供します。各タイプは抽象クラスRequest<T>を実装し、レスポンスを解析するメソッドを定義します。カスタム形式の場合は、parseNetworkResponseメソッドをオーバーライドして独自のタイプを作成できます。
| リクエストタイプ | 戻り値の型 | 目的 |
|---|---|---|
| StringRequest | String | 生のテキストレスポンスを取得 |
| JsonObjectRequest | JSONObject | JSONオブジェクトを解析 |
| JsonArrayRequest | JSONArray | JSON配列を解析 |
| ImageRequest | Bitmap | 画像の読み込みとデコード |
| ClearCacheRequest | — | Volleyキャッシュをクリア |
GsonやKotlinx Serializationを使用するには、parseNetworkResponseで選択したパーサーを使用するカスタムRequest<T>を作成できます。これにより、手動のJSONObject解析を回避して、型付けされたオブジェクトを直接受け取ることができます。このアプローチは、既にGsonやMoshiを介したシリアル化を使用しているプロジェクトで特に便利です。
データ送信のために、Volleyは3つのボディタイプをサポートしています:JSONObject(POSTメソッドのJsonObjectRequest経由)、Form-encoded(コンストラクタのHashMap<String, String>経由)、Multipart(カスタムMultipartRequest経由)。Multipartリクエストは画像やファイルのアップロードに便利ですが、VolleyにはOkHttpやDioとは異なり、multipart/form-dataの組み込みサポートがないため手動実装が必要です。
Volleyの制限は大きなレスポンスを扱う際に顕著になります。Volleyはコールバックに渡す前にレスポンス全体をメモリに読み込むため、10〜20MBを超えるJSONファイルではOutOfMemoryErrorを引き起こす可能性があります。大きなファイルのダウンロードにはVolleyは適していません — DownloadManagerまたはストリーミングResponseBodyを持つOkHttpを使用してください。Volleyは中断されたダウンロード(Rangeヘッダー)の再開をサポートせず、リアルタイムのServer-Sent EventsやWebSocketなどのストリーミングプロトコルとも動作しません。
基本的な例を見てみましょう — サーバーからデータを取得するStringRequestです。まず、Volley.newRequestQueue(context)を介してRequestQueueを作成します。次に、URLと成功・エラーのコールバックでリクエストを形成します。
val queue = Volley.newRequestQueue(context)
val request = StringRequest(
Request.Method.GET,
"https://api.github.com/users/octocat",
{ response ->
println("レスポンス: $response")
},
{ error ->
println("エラー: ${error.message}")
}
)
queue.add(request)
JSONリクエストには、レスポンスを自動的にJSONObjectに解析するJsonObjectRequestを使用します。VolleyはGETとPOSTリクエストをサポートしています。POSTの場合、リクエストボディにJSONObjectを渡します。
val jsonBody = JSONObject()
jsonBody.put("name", "New Repo")
jsonBody.put("description", "Created via Volley")
val request = JsonObjectRequest(
Request.Method.POST,
"https://api.github.com/user/repos",
jsonBody,
{ response ->
println("作成されました: ${response.getString("id")}")
},
{ println("エラー: $it") }
)
queue.add(request)
リクエストをキャンセルするには、cancel()メソッドまたはタグによるグループキャンセルを使用します。キャンセル時、VolleyはonResponseもonErrorResponseも呼び出さないため、画面離脱後のインターフェース更新を防ぎます。これはActivityやFragmentでのメモリリーク防止に重要です。
request.tag = "profile_request"
queue.add(request)
// 画面離脱時のキャンセル
queue.cancelAll("profile_request")
ImageLoaderはRequestQueueのラッパークラスで、画像読み込みに最適化されています。メモリキャッシュ(LruCache)をサポートし、RecyclerViewリストでImageViewが再利用される際に自動的にリクエストをキャンセルします。ImageLoaderはまた、Viewのサイズに合わせて画像をスケーリングし、メモリを節約します。
NetworkImageViewはImageLoaderと統合するカスタムViewで、読み込みを自動的に管理します:読み込み中はプレースホルダーを表示し、失敗時はエラーに置き換え、Viewが画面から離れるとリクエストをキャンセルします。DefaultImageUrlLoaderはURLで画像を読み込み、LruCacheに保存して迅速な再表示を実現します。
ImageLoaderを使用するには、ImageLoader(queue, ImageCache)を介してインスタンスを作成します。ここでImageCacheは内部にLruCacheを持つImageCacheインターフェースの実装です。XMLレイアウトのNetworkImageViewはsetImageUrl()メソッドを介してImageLoaderにリンクされ、プレースホルダーやエラー処理のための追加コードなしで、すべての読み込みが完全に自動的に行われます。
各ActivityでRequestQueueを作成することは、スレッドの重複とキャッシュの混乱を引き起こす一般的な間違いです。RequestQueueはApplicationで一度、またはシングルトンクラスを介して作成することをお勧めします。そうしないと、各画面が独自のスレッドプールを持ち、キャッシュがキューごとに別々に保存されます。
画面回転時のリクエストキャンセルの無視。設定変更時、Activityは再作成され、古いActivityのコールバックがメモリに残り続けます。これによりリークが発生し、破棄されたViewの更新が試みられます。常に、Activity固有のタグを使用してonStop()でcancelAll()によるリクエストキャンセルを行ってください。
VolleyはHTTP/2とコルーチンをサポートしていません — これは使用上のエラーではなく、アーキテクチャ上の制限です。Volleyは2013年に作成され、最新のプロトコルやKotlinコルーチンをサポートしていません。新しいプロジェクトでは、GoogleはRetrofit + OkHttpの使用を推奨しています。Volleyはレガシープロジェクトのサポートや、最小限のネットワーク要件を持つシンプルなアプリケーションにのみ適しています。
よくある質問
Volleyは新しいプロジェクトには時代遅れです — Googleは2017年以降ライブラリを更新していません。最新のアプリケーションには、Retrofit + OkHttpまたはKtor Clientを使用してください。Volleyは既存のレガシーコードのサポートや、最小限のネットワークタスクを持つシンプルな教育プロジェクトでのみ使用できます。
最新技術のサポート不足:HTTP/2、Kotlinコルーチン、マルチプラットフォーム開発、型付きシリアル化。Volleyは型なしのJSONObjectとJSONArrayを使用するため、JSON構造が期待と一致しない場合に実行時エラーが発生します。
ImageLoaderとNetworkImageViewを通じて。ImageLoaderは画像のメモリキャッシュにLruCacheを使用し、Viewが再利用される際に自動的にリクエストをキャンセルします。NetworkImageViewは読み込み中にプレースホルダーを表示し、読み込まれた画像またはエラーインジケーターに置き換えます。
技術的には可能です — VolleyのコールバックをsuspendCoroutine { }でラップすることで。しかし、Volleyはコルーチンのキャンセルに基づくキャンセルをサポートしておらず、Directly Dispatchers.IOとも連携しないため、利点はありません。ネイティブのコルーチンサポートを持つKtor Clientを使用することをお勧めします。
タイムアウトはRetryPolicyを介して設定します。デフォルトでは、DefaultRetryPolicyは2.5秒のタイムアウトと1回の再試行を使用します。パラメータ変更:request.retryPolicy = DefaultRetryPolicy(10000, 1, 1.0f) — 10秒のタイムアウト、1回の試行。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。