Volley容易学习使用二——Request

Volley简单学习使用二——Request
一、首先从每个POST或者GET请求的构造主体看起:XXXRequest
(一)StringRequest
源码如下:
public class StringRequest extends Request<String> {
    private final Listener<String> mListener;
 
    /**
     * 可以看到最终构造请求交由Request类去实现,HTTP的请求和响应均是由Request去处理
     *
     * @param method the request {@link Method} to use;method在Request中给出了定义
     * @param url URL to fetch the string at
     * @param listener Listener to receive the String response
     * @param errorListener Error listener, or null to ignore errors
     */
    public StringRequest(int method, String url, Listener<String> listener,
            ErrorListener errorListener) {
        super(method, url, errorListener);
        mListener = listener;
    }
 
    /** 默认为GET请求的构造函数*/
    public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
        this(Method.GET, url, listener, errorListener);
    }

    /** 这两个函数在父类Request均是abstract的*/
    // 将服务器响应的数据进行回调
    @Override
    protected void deliverResponse(String response) {
        mListener.onResponse(response);
    }

    // 对服务器响应发送的数据进行解析的函数,可以看到主体数据在NetworkResponse的data中
    // 很明显返回的success函数中第一个函数即是解析后的数据
    @Override
    protected Response<String> parseNetworkResponse(NetworkResponse response) {
        String parsed;
        try {
            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
        } catch (UnsupportedEncodingException e) {
            parsed = new String(response.data);
        }
        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
    }
}

(二)可以推理JSONObject也是相类似的实现,
public class JsonObjectRequest extends JsonRequest<JSONObject>
public abstract class JsonRequest<T> extends Request<T>

1、先看JsonObjectRequest的定义:
public class JsonObjectRequest extends JsonRequest<JSONObject> {
   /** 可以看到JsonObjectRequest最终构造请求也交由Request类去实现
    *  整个代码结构与StringRequest大同小异*/
    public JsonObjectRequest(int method, String url, JSONObject jsonRequest,
            Listener<JSONObject> listener, ErrorListener errorListener) {
        super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,
                    errorListener);
    }

    public JsonObjectRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener,
            ErrorListener errorListener) {
        this(jsonRequest == null ? Method.GET : Method.POST, url, jsonRequest,
                listener, errorListener);
    }
 
    /*deliverResponse在父类JsonRequest中给予了实现*/
    @Override
    protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
        try {
            String jsonString =
                new String(response.data, HttpHeaderParser.parseCharset(response.headers));
            return Response.success(new JSONObject(jsonString),
                    HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (JSONException je) {
            return Response.error(new ParseError(je));
        }
    }
}
2、查看JsonRequest
public abstract class JsonRequest<T> extends Request<T> {
    /** Request的编码格式. */
    private static final String PROTOCOL_CHARSET = "utf-8";
 
    /** Request的Content内容.*/
    private static final String PROTOCOL_CONTENT_TYPE =
        String.format("application/json; charset=%s", PROTOCOL_CHARSET);
 
    private final Listener<T> mListener;
    private final String mRequestBody;
 
    /**
     * Deprecated constructor for a JsonRequest which defaults to GET unless {@link #getPostBody()}
     * or {@link #getPostParams()} is overridden (which defaults to POST).
     */
    public JsonRequest(int method, String url, String requestBody, Listener<T> listener,
            ErrorListener errorListener) {
        super(method, url, errorListener);//这些均与StringRequest相类似,无非是多了mRequestBody
        mListener = listener;
        mRequestBody = requestBody;
    }
 
    @Override
    protected void deliverResponse(T response) {
        mListener.onResponse(response);
    }
 
    @Override
    abstract protected Response<T> parseNetworkResponse(NetworkResponse response);
 
    /** 这里重写了request中的相对应函数,来实现构造Request的具体内容 */
    @Override
    public String getBodyContentType() {
        return PROTOCOL_CONTENT_TYPE;
    }
 
    @Override
    public byte[] getBody() {
        try {
            return mRequestBody == null ? null : mRequestBody.getBytes(PROTOCOL_CHARSET);
        } catch (UnsupportedEncodingException uee) {
            VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s",
                    mRequestBody, PROTOCOL_CHARSET);
            return null;
        }
    }
}

(三)有上面可以总结出,构造XXXRequest的一般实践方式,

1、构造真正的Request交由父类Requset<XXX>去实现-- super(method, url, errorListener);

2、定义自己的Listener,用以deliverResponse

3、重写parseNetworkResponse函数来解析服务器响应返回的数据

(四)根据上面的分析,来定义自己的XXXRequest,比如XMLRequest来获取XML类型的返回数据,这里copy了

http://blog.csdn.net/guolin_blog/article/details/17612763中的代码

public class XMLRequest extends Request<XmlPullParser> {
 
    /*********这里讲T替换成所需要解析成的数据类型***********/
    private final Listener<XmlPullParser> mListener;
 
    /*********这里与前面所述的流程基本完全相同************************/
    public XMLRequest(int method, String url, Listener<XmlPullParser> listener,
            ErrorListener errorListener) {
        super(method, url, errorListener);
        mListener = listener;
    }
 
    public XMLRequest(String url, Listener<XmlPullParser> listener,
            ErrorListener errorListener) {
        this(Method.GET, url, listener, errorListener);
    }
 
    @Override
    protected Response<XmlPullParser> parseNetworkResponse(
            NetworkResponse response) {
        try {
            /***************实现新的XMLRequset核心在于此,解析数据返回的数据,用以获取最终的解析结果*********************/
            String xmlString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            XmlPullParser xmlPullParser = factory.newPullParser();
            xmlPullParser.setInput(new StringReader(xmlString));
            return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (XmlPullParserException e) {
            return Response.error(new ParseError(e));
        }
    }
 
    @Override
    protected void deliverResponse(XmlPullParser response) {
        mListener.onResponse(response);
    } 
}
其使用方式也与StringRequest大致相同,在Listener中可以添加对服务器response的数据的解析代码:
    private RequestQueue mRequestQueue;
   
    mRequestQueue = Volley.newRequestQueue(this);
    String url = "http://flash.weather.com.cn/wmaps/xml/china.xml";
 
    Response.Listener<XmlPullParser> listener = new Response.Listener<XmlPullParser>() {
        @Override
        public void onResponse(XmlPullParser response) {
            // 这里应该加上对于response的具体数据的解析
            Log.d(TAG, response.toString());
        }
    };
 
    Response.ErrorListener errorListener = new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Log.e(TAG, error.getMessage());
        }
    };
 
    XMLRequest xmlRequest = new XMLRequest(url, listener, errorListener);
    mRequestQueue.add(xmlRequest);

(五)回过头来看Request的原码

1、先看一下其构造函数,也是前面几个XXXRequest调用的构造函数:

public Request(int method, String url, Response.ErrorListener listener) {
    mMethod = method;                        // 成员变量赋值
    mUrl = url;
    mErrorListener = listener;
    setRetryPolicy(new DefaultRetryPolicy());// 设置重试策略
 
    mDefaultTrafficStatsTag = TextUtils.isEmpty(url) ? 0: Uri.parse(url).getHost().hashCode();
}
附I、重试策略
public class DefaultRetryPolicy implements RetryPolicy {
        ....
    /** The default socket timeout in milliseconds */
    public static final int DEFAULT_TIMEOUT_MS = 2500;//默认socket超时时间
    /** The default number of retries */
    public static final int DEFAULT_MAX_RETRIES = 1;  //默认重试次数
    /** The default backoff multiplier */
    public static final float DEFAULT_BACKOFF_MULT = 1f;//默认补偿系数
 
    public DefaultRetryPolicy() {
        this(DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_BACKOFF_MULT);
    }
        ....
}
setRetryPolicy即是一个简单的setter函数:
    /** The retry policy for this request. */
    private RetryPolicy mRetryPolicy;
 
    public void setRetryPolicy(RetryPolicy retryPolicy) {
        mRetryPolicy = retryPolicy;
    }
2、剩下的便是一连串的setter与getter函数,前面还用到的函数有:
    abstract protected Response<T> parseNetworkResponse(NetworkResponse response);   
    abstract protected void deliverResponse(T response);
可以看出这两个是abstract的,要求必须Override
3、JsonRequest中还Override了一些POST body相关函数,这些函数用以组织POST请求中的参数;具体使用时可以自行重载:
    private static final String DEFAULT_PARAMS_ENCODING = "UTF-8";
   
    protected Map<String, String> getParams() throws AuthFailureError {
        return null;
    }
   
    protected String getParamsEncoding() {
        return DEFAULT_PARAMS_ENCODING;
    }
 
    public String getBodyContentType() {
        return "application/x-www-form-urlencoded; charset=" + getParamsEncoding();
    }
 
    /**
     * Returns the raw POST or PUT body to be sent.
     */
    public byte[] getBody() throws AuthFailureError {
        Map<String, String> params = getParams();// 由上面getParams方法的定义可以看出,要使用本方法,
                                                 // 应该重载getParams方法,或者直接重载getBody()
        if (params != null && params.size() > 0) {
            return encodeParameters(params, getParamsEncoding());
        }
        returnnull;
    }
 
    /**
     * Converts <code>params</code> into an application/x-www-form-urlencoded encoded string.
     */
    privatebyte[] encodeParameters(Map<String, String> params, String paramsEncoding) {
        StringBuilder encodedParams = new StringBuilder();
        try {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                encodedParams.append(URLEncoder.encode(entry.getKey(), paramsEncoding));
                encodedParams.append('=');
                encodedParams.append(URLEncoder.encode(entry.getValue(), paramsEncoding));
                encodedParams.append('&');
            }
            return encodedParams.toString().getBytes(paramsEncoding);
        } catch (UnsupportedEncodingException uee) {
            thrownew RuntimeException("Encoding not supported: " + paramsEncoding, uee);
        }
    }