Volley—— 自定义Request

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Volley—— 自定义Request相关的知识,希望对你有一定的参考价值。

详细解读Volley(四)—— 自定义Request

Volley中提供了几个Request,如果我们有特殊的需求,完全可以自定义Request的,自定义Request自然要继承Request,那么本篇就教大家来一步一步地定义一个自己的Request类。

 

一、继承Request

如果我们的request的对象不是string,也不是JsonObject,而是一个奇怪的对象呢?我这里建立了一个类,叫做:Kale,然后定义了一个CustomReqeust去继承Reqeust,得到如下的代码。

技术分享
技术分享
package com.kale.volleytest;

import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;

public class CustomReqeust extends Request<Kale>{
    
    public CustomReqeust(int method, String url, ErrorListener listener) {
        super(method, url, listener);
    }

    @Override
    protected Response<Kale> parseNetworkResponse(NetworkResponse response) {
        // TODO 自动生成的方法存根
        return null;
    }

    @Override
    protected void deliverResponse(Kale response) {
        // TODO 自动生成的方法存根
        
    }

}
技术分享
技术分享

分析:

public CustomReqeust(int method, String url, ErrorListener listener)

构造函数中调用了父类的方法,初始化了当前对象。传入三个参数:①请求方式,即POST/GET,②请求的URL,③出错时的回调监听器

 

protected Response<Kale> parseNetworkResponse(NetworkResponse response)

解析网络响应的结果,从NetworkResponse的代码中我们就可以知道它里面有什么东西了。

技术分享
技术分享
/**
 * Data and headers returned from {@link Network#performRequest(Request)}.
 */
public class NetworkResponse {
    /**
     * Creates a new network response.
     * @param statusCode the HTTP status code
     * @param data Response body
     * @param headers Headers returned with this response, or null for none
     * @param notModified True if the server returned a 304 and the data was already in cache
     * @param networkTimeMs Round-trip network time to receive network response
     */
    public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
            boolean notModified, long networkTimeMs)
技术分享
技术分享

响应码啊,请求头什么的,最最主要的就是这个比特数组的data,响应的结果就在里面。我们可以自由的进行处理了~

 

protected void deliverResponse(Kale response)

分发响应的结果,我们可以通过将这个response放到监听器里来获取响应结果。

 

二、分析StringRequest

我们现在已经对request的子类有了基本的认识,现在就来看看StringRequest的源码吧,别担心,很短!

技术分享
技术分享
package com.android.volley.toolbox;public class StringRequest extends Request<String> {
    // 建立监听器来获得响应成功时返回的结果
    private final Listener<String> mListener; 


    // 传入请求方法,url,成功时的监听器,失败时的监听器
    public StringRequest(int method, String url, Listener<String> listener,
            ErrorListener errorListener) {
        super(method, url, errorListener);
        // 初始化成功时的监听器
        mListener = listener;
    }

    /**
     * Creates a new GET request.
     * 建立一个默认的GET请求,调用了上面的构造函数
     */
    public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
        this(Method.GET, url, listener, errorListener);
    }

    @Override
    protected void deliverResponse(String response) {
        // 用监听器的方法来传递下响应的结果
        mListener.onResponse(response);
    }

    @Override
    protected Response<String> parseNetworkResponse(NetworkResponse response) {
        String parsed;
        try {
            // 调用了new String(byte[] data, String charsetName) 这个构造函数来构建String对象,
            // 将byte数组按照特定的编码方式转换为String对象
            // 主要部分是data
            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
        } catch (UnsupportedEncodingException e) {
            parsed = new String(response.data);
        }
        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
    }
}
技术分享
技术分享

分析完代码我们应该就能知道改如何自定义Request了,其实没啥高深的东西。

 

三、自定义XMLRequest

代码来自:http://blog.csdn.net/guolin_blog/article/details/17612763

技术分享
技术分享
public class XMLRequest extends Request<XmlPullParser> {  
  
    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 {  
            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);  
    }  
  
} 
技术分享
技术分享

这里用到了XmlPull的知识,如果不是很了解,可以去这篇文章看看:http://www.cnblogs.com/tianzhijiexian/p/4020250.html

测试代码:

技术分享
技术分享
XMLRequest xmlRequest = new XMLRequest(  
                "http://flash.weather.com.cn/wmaps/xml/china.xml",  
                new Response.Listener<XmlPullParser>() {  
                    @Override  
                    public void onResponse(XmlPullParser response) {  
                        try {  
                            int eventType = response.getEventType();  
                            while (eventType != XmlPullParser.END_DOCUMENT) {  
                                switch (eventType) {  
                                case XmlPullParser.START_TAG:  
                                    String nodeName = response.getName();  
                                    if ("city".equals(nodeName)) {  
                                        String pName = response.getAttributeValue(0);  
                                        Log.d("TAG", "pName is " + pName);  
                                    }  
                                    break;  
                                }  
                                eventType = response.next();  
                            }  
                        } catch (XmlPullParserException e) {  
                            e.printStackTrace();  
                        } catch (IOException e) {  
                            e.printStackTrace();  
                        }  
                    }  
                }, new Response.ErrorListener() {  
                    @Override  
                    public void onErrorResponse(VolleyError error) {  
                        Log.e("TAG", error.getMessage(), error);  
                    }  
                });  
        mQueue.add(xmlRequest);
技术分享
技术分享

结果:

技术分享

 

四、自定义GsonRequest

代码来自:http://blog.csdn.net/guolin_blog/article/details/17612763

技术分享
技术分享
public class GsonRequest<T> extends Request<T> {

    private final Listener<T> mListener;

    private Gson mGson;

    private Class<T> mClass;

    public GsonRequest(int method, String url, Class<T> clazz, Listener<T> listener,
            ErrorListener errorListener) {
        super(method, url, errorListener);
        mGson = new Gson();
        mClass = clazz;
        mListener = listener;
    }

    public GsonRequest(String url, Class<T> clazz, Listener<T> listener,
            ErrorListener errorListener) {
        this(Method.GET, url, clazz, listener, errorListener);
    }

    @Override
    protected Response<T> parseNetworkResponse(NetworkResponse response) {
        try {
            String jsonString = new String(response.data,
                    HttpHeaderParser.parseCharset(response.headers));
            return Response.success(mGson.fromJson(jsonString, mClass),
                    HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        }
    }

    @Override
    protected void deliverResponse(T response) {
        mListener.onResponse(response);
    }

}
技术分享
技术分享

代码十分简单,先是将服务器响应的数据解析出来,然后通过调用Gson的fromJson方法将数据组装成对象。在deliverResponse方法中仍然是将最终的数据进行回调。

用法:

建立一个对象类,比如这里的weather、WeatherInfo类,然后初始化GsonRequest对象,最后把GsonRequest对象添加到队列中。

Weather:

 

public class Weather {

    private WeatherInfo weatherinfo;

    public WeatherInfo getWeatherinfo() {
        return weatherinfo;
    }

    public void setWeatherinfo(WeatherInfo weatherinfo) {
        this.weatherinfo = weatherinfo;
    }

}

 

 

 

WeatherInfo:

 

public class WeatherInfo {

    private String city;

    private String temp;

    private String time;

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getTemp() {
        return temp;
    }

    public void setTemp(String temp) {
        this.temp = temp;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }

}

 

 

 

 

Java测试代码:

技术分享
技术分享
GsonRequest<Weather> gsonRequest = new GsonRequest<Weather>(  
        "http://www.weather.com.cn/data/sk/101010100.html", Weather.class,  
        new Response.Listener<Weather>() {  
            @Override  
            public void onResponse(Weather weather) {  
                WeatherInfo weatherInfo = weather.getWeatherinfo();  
                Log.d("TAG", "city is " + weatherInfo.getCity());  
                Log.d("TAG", "temp is " + weatherInfo.getTemp());  
                Log.d("TAG", "time is " + weatherInfo.getTime());  
            }  
        }, new Response.ErrorListener() {  
            @Override  
            public void onErrorResponse(VolleyError error) {  
                Log.e("TAG", error.getMessage(), error);  
            }  
        });  
mQueue.add(gsonRequest); 
技术分享
技术分享

 

五、重写getBody()方法来添加post参数

我们可以在JsonRequest类中发现如下代码:

技术分享
技术分享
/** 
  * Returns the raw POST or PUT body to be sent. 
  * 
  * @throws AuthFailureError in the event of auth failure 
  */  
 @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;  
     }  
 }  
技术分享
技术分享

不用看代码,直接看注释,说明这里执行post请求,所以我们可以在这里设置post参数。这里

return mRequestBody == null ? null : mRequestBody.getBytes(PROTOCOL_CHARSET); 

返回的就是post参数了。

如果我们想要传递POST数据,可以参考上面的代码,重写Request的getBody()方法,放入自己的参数,举例如下:

技术分享
技术分享
   /** http请求编码方式 */  
    private static final String PROTOCOL_CHARSET = "utf-8";  
  
    private String mUserName; 
技术分享
技术分享
技术分享
技术分享
@Override  
    public byte[] getBody() {  
        try {  
            return mUserName == null ? null : mUserName.getBytes(PROTOCOL_CHARSET);  
        } catch (UnsupportedEncodingException uee) {  
            VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", mUserName, PROTOCOL_CHARSET);  
            return null;  
        }  
    }  
技术分享
技术分享

完整代码(来自:http://blog.csdn.net/ttdevs/article/details/17586205):

 

技术分享
public class CustomReqeust extends Request<String> {  
    /** http请求编码方式 */  
    private static final String PROTOCOL_CHARSET = "utf-8";  
  
    private Listener<String> mListener;  
    private String mUserName;  
  
    public CustomReqeust(String url, String userName, Listener<String> listener, ErrorListener errorListener) {  
        super(Method.POST, url, errorListener);  
        mUserName = userName;  
        mListener = listener;  
    }  
  
    @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));  
    }  
  
    @Override  
    protected void deliverResponse(String response) {  
        mListener.onResponse(response);  
    }  
  
    @Override  
    public byte[] getBody() {  
        try {  
            return mUserName == null ? null : mUserName.getBytes(PROTOCOL_CHARSET);  
        } catch (UnsupportedEncodingException uee) {  
            VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", mUserName, PROTOCOL_CHARSET);  
            return null;  
        }  
    }  
}
技术分享

 

 

 

测试代码:

技术分享
技术分享
private void customRequest() {  
    CustomReqeust request = new CustomReqeust(URL, "CustomVolley", new Listener<String>() {  
  
        @Override  
        public void onResponse(String arg0) {  
            Toast.makeText(getApplicationContext(), arg0, Toast.LENGTH_LONG).show();  
            Log.d("onResponse", arg0);  
        }  
    }, new ErrorListener() {  
  
        @Override  
        public void onErrorResponse(VolleyError arg0) {  
            Toast.makeText(getApplicationContext(), arg0.toString(), Toast.LENGTH_LONG).show();  
            Log.d("onErrorResponse", arg0.toString());  
        }  
    });  
    mQueue.add(request);  
}  
技术分享
技术分享

抓包结果:

技术分享

得到了传递的username = CustomVolley

以上是关于Volley—— 自定义Request的主要内容,如果未能解决你的问题,请参考以下文章

Volley详解+源码分析

安卓中自定义并使用Volley框架请求网络

在 volley 中设置查询字符串不起作用

Volley源码分析之自定义MultiPartRequest(文件上传)

Android--Volley基本用法及自定义

JSP自定义标签