カスタム リクエストを実装する

このレッスンでは、Volley がネイティブでサポートしていないタイプに対して、独自のカスタム リクエスト タイプを実装する方法について説明します。

カスタム リクエストを作成する

ほとんどのリクエストに関して、すぐに使用できる実装がツールボックス内に用意されています。レスポンスが文字列や、画像、JSON のいずれかの場合、通常はカスタム Request を実装する必要はありません。

カスタム リクエストを実装する必要がある場合、以下の設定を行う必要があります。

  • Request<T> クラスを拡張します。<T> は、リクエストが想定する解析対象レスポンスのタイプを示します。たとえば、解析対象レスポンスが文字列の場合は、Request<String> を拡張してカスタム リクエストを作成します。Request<T> を拡張する例については、Volley ツールボックス クラスの StringRequestImageRequest をご覧ください。
  • 抽象メソッドの 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 クラスを使用することもできます。詳細については、標準リクエストを作成するをご覧ください。