このレッスンでは、Volley がネイティブでサポートしていないタイプに対して、独自のカスタム リクエスト タイプを実装する方法について説明します。
カスタム リクエストを作成する
ほとんどのリクエストに関して、すぐに使用できる実装がツールボックス内に用意されています。レスポンスが文字列や、画像、JSON のいずれかの場合、通常はカスタムRequest
を実装する必要はありません。
カスタム リクエストを実装する必要がある場合、以下の設定を行う必要があります。
Request<T>
クラスを拡張します。<T>
は、リクエストが想定する解析対象レスポンスのタイプを示します。たとえば、解析対象レスポンスが文字列の場合は、Request<String>
を拡張してカスタム リクエストを作成します。Request<T>
を拡張する例については、Volley ツールボックス クラスのStringRequest
とImageRequest
をご覧ください。- 抽象メソッドの
parseNetworkResponse()
とdeliverResponse()
を実装します(下記を参照)。
parseNetworkResponse
Response
は、指定タイプ(文字列、画像、JSON など)を対象として、解析対象レスポンスを配信用にカプセル化します。parseNetworkResponse()
のサンプル実装を以下に示します。
Kotlin
override fun parseNetworkResponse(response: NetworkResponse?): Response<T> { return try { val json = String( response?.data ?: ByteArray(0), Charset.forName(HttpHeaderParser.parseCharset(response?.headers))) Response.success( gson.fromJson(json, clazz), HttpHeaderParser.parseCacheHeaders(response)) } // handle errors // ... }
Java
@Override protected Response<T> parseNetworkResponse( NetworkResponse response) { try { String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); return Response.success(gson.fromJson(json, clazz), HttpHeaderParser.parseCacheHeaders(response)); } // handle errors // ... }
注:
parseNetworkResponse()
はNetworkResponse
をパラメータとして取ります。これには、レスポンス ペイロードが byte[]、HTTP ステータス コード、レスポンス ヘッダーとして含まれます。- 実装は
Response<T>
を返す必要があります。これには、型付けされたレスポンス オブジェクトとキャッシュ メタデータが含まれます(解析が失敗した場合などでは、エラーが含まれます)。
プロトコルに非標準のキャッシュ セマンティクスがある場合は、Cache.Entry
を自分で作成できます。ただし、ほとんどのリクエストでは、次のような指定で対処できます。
Kotlin
return Response.success(myDecodedObject, HttpHeaderParser.parseCacheHeaders(response))
Java
return Response.success(myDecodedObject, HttpHeaderParser.parseCacheHeaders(response));
Volley はワーカー スレッドから parseNetworkResponse()
を呼び出します。そのため、JPEG からビットマップへのデコードなど、コストの高い解析処理が UI スレッドをブロックすることはありません。
deliverResponse
Volley は、parseNetworkResponse()
で返されたオブジェクトに対してメインスレッドでコールバックします。ほとんどのリクエストでは、ここでコールバック インターフェースを呼び出します。たとえば、次のようになります。
Kotlin
override fun deliverResponse(response: T) = listener.onResponse(response)
Java
protected void deliverResponse(T response) { listener.onResponse(response);
例: GsonRequest
Gson は、リフレクションを使用して Java オブジェクトと JSON 間を変換するためのライブラリです。対応する JSON キーと同じ名前を持つ Java オブジェクトを定義して、そのクラス オブジェクトを Gson に渡し、Gson にそのフィールドに入力してもらうことができます。Gson を解析に使用する Volley リクエストの実装全体を次に示します。
Kotlin
/** * Make a GET request and return a parsed object from JSON. * * @param url URL of the request to make * @param clazz Relevant class object, for Gson's reflection * @param headers Map of request headers */ class GsonRequest<T>( url: String, private val clazz: Class<T>, private val headers: MutableMap<String, String>?, private val listener: Response.Listener<T>, errorListener: Response.ErrorListener ) : Request<T>(Method.GET, url, errorListener) { private val gson = Gson() override fun getHeaders(): MutableMap<String, String> = headers ?: super.getHeaders() override fun deliverResponse(response: T) = listener.onResponse(response) override fun parseNetworkResponse(response: NetworkResponse?): Response<T> { return try { val json = String( response?.data ?: ByteArray(0), Charset.forName(HttpHeaderParser.parseCharset(response?.headers))) Response.success( gson.fromJson(json, clazz), HttpHeaderParser.parseCacheHeaders(response)) } catch (e: UnsupportedEncodingException) { Response.error(ParseError(e)) } catch (e: JsonSyntaxException) { Response.error(ParseError(e)) } } }
Java
public class GsonRequest<T> extends Request<T> { private final Gson gson = new Gson(); private final Class<T> clazz; private final Map<String, String> headers; private final Listener<T> listener; /** * Make a GET request and return a parsed object from JSON. * * @param url URL of the request to make * @param clazz Relevant class object, for Gson's reflection * @param headers Map of request headers */ public GsonRequest(String url, Class<T> clazz, Map<String, String> headers, Listener<T> listener, ErrorListener errorListener) { super(Method.GET, url, errorListener); this.clazz = clazz; this.headers = headers; this.listener = listener; } @Override public Map<String, String> getHeaders() throws AuthFailureError { return headers != null ? headers : super.getHeaders(); } @Override protected void deliverResponse(T response) { listener.onResponse(response); } @Override protected Response<T> parseNetworkResponse(NetworkResponse response) { try { String json = new String( response.data, HttpHeaderParser.parseCharset(response.headers)); return Response.success( gson.fromJson(json, clazz), HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JsonSyntaxException e) { return Response.error(new ParseError(e)); } } }
Volley が提供する JsonArrayRequest
クラスと JsonArrayObject
クラスを使用することもできます。詳細については、標準リクエストを作成するをご覧ください。