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

简介: 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()

相关文章
|
23天前
|
人工智能 自然语言处理 Shell
🦞 如何在 OpenClaw (Clawdbot/Moltbot) 配置阿里云百炼 API
本教程指导用户在开源AI助手Clawdbot中集成阿里云百炼API,涵盖安装Clawdbot、获取百炼API Key、配置环境变量与模型参数、验证调用等完整流程,支持Qwen3-max thinking (Qwen3-Max-2026-01-23)/Qwen - Plus等主流模型,助力本地化智能自动化。
33663 134
🦞 如何在 OpenClaw (Clawdbot/Moltbot) 配置阿里云百炼 API
|
6天前
|
人工智能 自然语言处理 监控
OpenClaw skills重构量化交易逻辑:部署+AI全自动炒股指南(2026终极版)
2026年,AI Agent领域最震撼的突破来自OpenClaw(原Clawdbot)——这个能自主规划、执行任务的智能体,用50美元启动资金创造了48小时滚雪球至2980美元的奇迹,收益率高达5860%。其核心逻辑堪称教科书级:每10分钟扫描Polymarket近千个预测市场,借助Claude API深度推理,交叉验证NOAA天气数据、体育伤病报告、加密货币链上情绪等多维度信息,捕捉8%以上的定价偏差,再通过凯利准则将单仓位严格控制在总资金6%以内,实现低风险高频套利。
2767 11
|
19天前
|
人工智能 安全 机器人
OpenClaw(原 Clawdbot)钉钉对接保姆级教程 手把手教你打造自己的 AI 助手
OpenClaw(原Clawdbot)是一款开源本地AI助手,支持钉钉、飞书等多平台接入。本教程手把手指导Linux下部署与钉钉机器人对接,涵盖环境配置、模型选择(如Qwen)、权限设置及调试,助你快速打造私有、安全、高权限的专属AI助理。(239字)
7248 21
OpenClaw(原 Clawdbot)钉钉对接保姆级教程 手把手教你打造自己的 AI 助手
|
17天前
|
人工智能 机器人 Linux
OpenClaw(Clawdbot、Moltbot)汉化版部署教程指南(零门槛)
OpenClaw作为2026年GitHub上增长最快的开源项目之一,一周内Stars从7800飙升至12万+,其核心优势在于打破传统聊天机器人的局限,能真正执行读写文件、运行脚本、浏览器自动化等实操任务。但原版全英文界面对中文用户存在上手门槛,汉化版通过覆盖命令行(CLI)与网页控制台(Dashboard)核心模块,解决了语言障碍,同时保持与官方版本的实时同步,确保新功能最快1小时内可用。本文将详细拆解汉化版OpenClaw的搭建流程,涵盖本地安装、Docker部署、服务器远程访问等场景,同时提供环境适配、问题排查与国内应用集成方案,助力中文用户高效搭建专属AI助手。
5114 12
|
20天前
|
人工智能 机器人 Linux
保姆级 OpenClaw (原 Clawdbot)飞书对接教程 手把手教你搭建 AI 助手
OpenClaw(原Clawdbot)是一款开源本地AI智能体,支持飞书等多平台对接。本教程手把手教你Linux下部署,实现数据私有、系统控制、网页浏览与代码编写,全程保姆级操作,240字内搞定专属AI助手搭建!
5892 23
保姆级 OpenClaw (原 Clawdbot)飞书对接教程 手把手教你搭建 AI 助手

热门文章

最新文章