转自http://www.bubuko.com/infodetail-712004.html ,非常感谢这篇文章,帮我解决了此问题,so记录一下。
我遇到的问题基本上和文章中写的一样,只不过他用的是JsonObjecetRequest,我用的StringRequest,都是一个父类,所以是一样的。
为了避免一些不可控因素,我还是把原文稍微的复制一下,以供以后查阅。
今天在项目中使用Volley作为网络通信框架,却发现在传输中文时会出现乱码。也是百度了很久,偶然看到上面链接的文章,才得以解决。
首先,服务器返回的数据,编码格式肯定是utf-8的,电脑端浏览器请求测试都没有问题,询问服务端人员也说返回的就是utf-8,那是为什么在Android端会出现乱码的现象呢。
我在想(其实是他在想...)是不是本地端的字符编码出了问题?
我就是用String类的转码功能,发现不起作用。
一筹莫展。
我去网上搜索了一下,大部分都是volley默认采用的是UTF8的字符编码格式。可是服务器返回来的UTF-8的字符串为什么就是显示乱码呢。
接着我就想到了查看volley的源代码。
我发现volley的整个框架的结构是这个样子的,首先Android端构造不同类型的request对象,总得来说有这几大类:
JSONObjectRequest
JSONArrayRequest
StringRequest
它们都有一个共同的基类——Reuqest。所有继承Request的子类都必须覆盖以下两个方法:
protected Response<T> parseNetworkResponse(NetworkResponse response);
protected void deliverResponse(T response);
第一个方法是用来解析服务器返回的原始数据。response对象包含了返回数据的body、headers等内容,需要在该方法中对返回数据进行解析。比如JSONObjectRequest就是使用response中的body字符串
构造一个JSONObject对象,传递给监听器的对象。这样的设计默认了消息的发送者必将知道服务器的返回是如何解析的这一潜规则。
接着,我就查看了一下JSONOBjectReuqest类中的parseNetworkResponse方法,看看它在将结果传递给监听器之前做了什么。
源代码如下:
@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));
}
}
我们看到了,JSONObjectRequest这个类在将数据返回给监听器之前,是对字符串进行了转码的。我们貌似接近了问题的本质。那就接着查看HttpHeaderParser.parseCacheHeaders(response),是怎么获取字符集的。我猜想里面肯定包含了默认的字符集的定义。
打开代码:
/**
* Returns the charset specified in the Content-Type of this header,
* or the HTTP default (ISO-8859-1) if none can be found.
*/
public static String parseCharset(Map<String, String> headers) {
String contentType = headers.get(HTTP.CONTENT_TYPE);
if (contentType != null) {
String[] params = contentType.split(";");
for (int i = 1; i < params.length; i++) {
String[] pair = params[i].trim().split("=");
if (pair.length == 2) {
if (pair[0].equals("charset")) {
return pair[1];
}
}
}
}
return HTTP.DEFAULT_CONTENT_CHARSET;
}
看到了注释,一切都水落石出了,原来,如果在服务器的返回数据的header中没有指定字符集那么就会默认使用 ISO-8859-1 字符集。
ISO-8859-1的别名叫做Latin1。这个字符集支持部分是用于欧洲的语言,不支持中文~
很不能理解为什么将这个字符集作为默认的字符集。Volley这个框架可是要用在网络通信的环境中的。
吐槽也没有用,我们来看一下如何来解决中文乱码的问题。有以下几种解决方式:
1.在服务器的返回的数据的header的中contentType加上charset=UTF-8的声明。
2.当你无法修改服务器程序的时候,可以定义一个新的子类。覆盖parseNetworkResponse这个方法,直接使用UTF-8对服务器的返回数据进行转码。
接下来我给服务端人员说,他说后台改起来很麻烦...,然后我就按照文章介绍 去看了一下源码,最后新建了一个类,继承StringRequest类,然后重写它的
parseNetworkResponse()方法:
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
<span style="color:#ff0000;"> parsed = new String(response.data, "utf-8");</span>
} catch (UnsupportedEncodingException e) {
parsed = new String(response.data);
}
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
使用的时候就用你自己新建的那个类就行了。比如我建的类叫MyStringRequest 继承自StringRequest,用的时候就直接 MyStringRequest request = new MyStringRequest ();里面几个参数我就不写了。