Volley学习笔记 | 关于源码中Request、Response、Listener泛型的理解(附XMLRequest自定义代码)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: Volley学习笔记 | 关于源码中Request、Response、Listener泛型的理解(附XMLRequest自定义代码)

小结Volley中Response从接收到转换成业务的过程

  • parseNetworkResponse()

是对Response进行第一步的解析——
服务器的响应数据组织成对应类型Request类型Response

  • 然后这个Response会传给Response.success()

Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response));

  • 接着会在deliverResponse()

将这个response传给mListener.onResponse()
mListener.onResponse(response);

  • 在使用的时候,

我们常规操作是实例化一个类型Request
实例化时(new过程)传给了构造方法的
是一个重写了onResponse()Listener<对应类型>实例
也就是说,
**我们在实例化一个类型Request的时候,
重写onResponse(),**
**在onResponse()其中,
Response进行了第二次解析——**
**即,把首次解析组织好的数据/对象
提现成具体的业务实现;
这里`@Override

                public void onResponse(对应类型response)`的`onResponse(对应类型response)`和

我们自己实例化
构造的Listenernew Response.Listener<对应类型>(){@Override...}
其实跟框架源码中deliverResponse()mListener.onResponse(response);Listener、onResponse、response逻辑上是对应的;**

  • **话不多说,理解了这个几个泛型之间的联系,

也就能把Volley框架中自定义Request的步骤过程和原理理解个七七八八;
下面围绕泛型之间的联系展开笔记,
同时关联到了Volley中Response从接收到转换成业务的过程描述;**

首先看下StringRequest的源码,如下所示:

/**
 * A canned request for retrieving the response body at a given URL as a String.
 */
public class StringRequest extends Request<String> {
    private final Listener<String> mListener;
 
    /**
     * Creates a new request with the given method.
     *
     * @param method the request {@link Method} to use
     * @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;
    }
 
    /**
     * Creates a new GET 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(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 {
            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源码中的parseNetworkResponse()

是对Response进行第一步的解析——
服务器的响应数据组织成对应类型Request类型Response
如:

- ```StringRequest```中的```parseNetworkResponse()```

把服务器的响应数据组织成String类型,
Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
( Response<String> parseNetworkResponse(NetworkResponse response),String parsed);

ImageRequestbitmap
Response.success(bitmap, HttpHeaderParser.parseCacheHeaders(response));
(Response<Bitmap> parseNetworkResponse(NetworkResponse response) )

XMLRequestXmlPullParser
Response<XmlPullParser> parseNetworkResponse(NetworkResponse response)

@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));
    }
  • 然后这个Response会传给Response.success()

Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response));

  • 接着会在deliverResponse()中

将这个response传给mListener.onResponse()

    @Override
    protected void deliverResponse(String response) {
        mListener.onResponse(response);
    }
  • 在实例化一个类型Request的时候,

我们传给了构造方法一个重写了onResponse()Listener<对应类型>
也就是说,
**我们在实例化一个类型Request的时候,
在重写的onResponse()中,**
Response进行了第二次解析——
**即,把首次解析组织好的数据/对象
提现成具体的业务实现;**

下面是XMLRequest的自定义代码与使用例程:

  • 使用例程:
        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);

                                            reponseContent += pName;
                                            reponseContent += "\n";
                                        }
                                        break;
                                }
                                eventType = response.next();
                            }
                            oriString = new String(reponseContent.getBytes("ISO-8859-1"), "utf-8");
                            responseText.setText(oriString);
                        } 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);
  • XMLRequest的自定义代码:
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);
    }
 
}

附上写demo时候遇到的两个bug,以及相关的解决办法的文章:

网络安全配置问题:

xml解析结果乱码
解决方法:
new String(reponseContent.getBytes("ISO-8859-1"), "utf-8");
相关文章:

  • **小结一下,

总而言之我们可以看到,
public class XMLRequest extends Request<XmlPullParser>
Request<XmlPullParser>的泛型,
protected Response<XmlPullParser> parseNetworkResponse(NetworkResponse response)
Response<XmlPullParser> 的泛型,
private final Listener<XmlPullParser> mListener;
Listener<XmlPullParser>的泛型,
都是一致的,
是因,**

- **```Request<XmlPullParser>```的泛型指定自定义二级Request的类型,**
- **```Response<XmlPullParser>```的泛型表明

parseNetworkResponse()进行第一步解析的返回结果类型,
把服务器的响应数据组织成对应类型Request的类型;**

- **```Listener<XmlPullParser>```的泛型

对应着Listener传递的Response的类型,
也即表明二次解析提现业务时的操作对象(即Response,第一步解析的返回结果类型)
也即onResponse()的参数类型**

  • 另外,

自定义Gson的时候,因为类型不明确,所以用T占位,
使用时用对应的类作为参数即可:
如例程:
Response.success(mGson.fromJson(jsonString, mClass)
mGson.fromJson(jsonString, mClass)
mClass(private Class<T> mClass;)
对应gson.fromJson(jsonData, new TypeToken<List<T>>(){}.getType());中的
new TypeToken<List<T>>(){}.getType()

相关文章
|
6月前
通过 Filter 与包装 HttpServletRequest 添加自定义 header
通过 Filter 与包装 HttpServletRequest 添加自定义 header
390 0
|
存储 API
10JavaWeb基础 - Request类
10JavaWeb基础 - Request类
58 0
|
Java Apache 网络架构
【小家Spring】Feign发送Get请求时,采用POJO对象传递参数的最终解决方案 Request method ‘POST‘ not supported (附带其余好几个坑)(上)
【小家Spring】Feign发送Get请求时,采用POJO对象传递参数的最终解决方案 Request method ‘POST‘ not supported (附带其余好几个坑)
|
缓存 JSON 数据格式
OkHttp3源码详解(一) Request类
阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680每一次网络请求都是一个Request,Request是对url,method,header,body的封装,也是对Http协议中请求行,请求头,实体内容的封装 p.
|
存储 JSON 前端开发
【小家Java】Servlet规范之---请求(request):Servlet中如何获取POST请求参数?(使用getParameter())
【小家Java】Servlet规范之---请求(request):Servlet中如何获取POST请求参数?(使用getParameter())
【小家Java】Servlet规范之---请求(request):Servlet中如何获取POST请求参数?(使用getParameter())
|
负载均衡 Java Spring
【小家Spring】Feign发送Get请求时,采用POJO对象传递参数的最终解决方案 Request method ‘POST‘ not supported (附带其余好几个坑)(下)
【小家Spring】Feign发送Get请求时,采用POJO对象传递参数的最终解决方案 Request method ‘POST‘ not supported (附带其余好几个坑)(下)
【小家Spring】Feign发送Get请求时,采用POJO对象传递参数的最终解决方案 Request method ‘POST‘ not supported (附带其余好几个坑)(下)
Servlet第四篇【request对象常用方法、应用】(一)
HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,开发人员通过这个对象的方法,可以获得客户这些信息。
143 0
Servlet第四篇【request对象常用方法、应用】(一)
|
应用服务中间件
Servlet第四篇【request对象常用方法、应用】(三)
HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,开发人员通过这个对象的方法,可以获得客户这些信息。
125 0
Servlet第四篇【request对象常用方法、应用】(三)
|
Java 应用服务中间件
Servlet第四篇【request对象常用方法、应用】(五)
HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,开发人员通过这个对象的方法,可以获得客户这些信息。
174 0
Servlet第四篇【request对象常用方法、应用】(五)