Android ByteArrayOutputStream 损坏 HTTP GET JSONArray
Android ByteArrayOutputStream corrupting HTTP GET JSONArray
我正在使用此代码来解析从我的服务器获取的 JSON 数组。
try {
URL u = new URL("http://54.68.139.250/get_user_likes");
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
conn.setRequestMethod("GET");
conn.connect();
InputStream is = conn.getInputStream();
byte[] b = new byte[1024];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ( is.read(b) != -1)
baos.write(b);
String JSONResp = new String(baos.toByteArray());
JSONArray arr = new JSONArray(JSONResp);
for (int i=0; i < arr.length(); i++) {
result.add(convertArticle(arr.getJSONObject(i)));
}
return result;
}
catch(Throwable t) {
t.printStackTrace();
}
return null;
此代码在我的 phone 上运行良好。不幸的是,当我将 Genymotion 模拟器与 Google Nexus 7 的虚拟设备一起使用时,JSON 数组略有改变。 JSON 数组的 95% 都很好,但它在接近尾部的地方被截断并且在字符 1253 处随机丢失了 json 数组的大约 4 个字符,所以我得到:
org.json.JSONException: Expected ':' after top_id at character 1253 of [{"top_id":6,"top_url":
我认为这是模拟器的内存问题。它的基本内存是 1024。增加这个数量并没有改变任何东西。
任何关于问题背后原因的提示将不胜感激。另外,如果您认为有改进的余地,请随时评论我的代码。 :)
真奇怪。
我可以想到两件事来尝试:
- 检查服务器的编码和String构造函数的编码。
服务器可能使用 Latin-1 (ISO-8859-1) 进行解码,而字符串使用 UTF-8 进行编码。但是 JSON 应该以 Unicode 发送,而 Android 的默认字符集是 UTF-8。检查 HTTP Content-type 响应头;它应该说:application/json; charset=utf-8
。如果 charset
部分不存在,请进行一些调查并找出您的服务器用于解码为 HTTP 流的字符集。并检查 phone 和模拟器上的默认字符集是否相同;它应该是UTF-8。
- 在读取数据之后构造字符串之前,尝试在 ByteArrayOutputStream 上调用
flush()
。
可能 phone OS 和模拟器 OS 在流数据 transferred/buffered/flushed.
上存在细微差别
如果 flush()
不起作用,请尝试在不使用 ByteArrayOutputStream 的情况下重写代码。例如,您可以用 InputStreamReader
包装输入流,它读取字符而不是字节,然后使用 StringBuilder
或 StringBuffer
.
附加字符
使代码更好的一种方法是使用 JSONReader
而不是 JSONArray
或 JSONObject
。 JSONReader
将包装一个 InputStreamReader
,后者又包装 HTTP 输入流。它可以更快并且更有效地存储内存,因为您不必在开始解析数据之前读取整个输入流。当服务器发送大量 JSON 数据时,情况会大不相同。
您应该检查 is.read()
的 return 值。变化
while ( is.read(b) != -1)
baos.write(b);
至
int nread;
while ( (nread=is.read(b)) != -1)
baos.write(b, 0, nread);
我正在使用此代码来解析从我的服务器获取的 JSON 数组。
try {
URL u = new URL("http://54.68.139.250/get_user_likes");
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
conn.setRequestMethod("GET");
conn.connect();
InputStream is = conn.getInputStream();
byte[] b = new byte[1024];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ( is.read(b) != -1)
baos.write(b);
String JSONResp = new String(baos.toByteArray());
JSONArray arr = new JSONArray(JSONResp);
for (int i=0; i < arr.length(); i++) {
result.add(convertArticle(arr.getJSONObject(i)));
}
return result;
}
catch(Throwable t) {
t.printStackTrace();
}
return null;
此代码在我的 phone 上运行良好。不幸的是,当我将 Genymotion 模拟器与 Google Nexus 7 的虚拟设备一起使用时,JSON 数组略有改变。 JSON 数组的 95% 都很好,但它在接近尾部的地方被截断并且在字符 1253 处随机丢失了 json 数组的大约 4 个字符,所以我得到:
org.json.JSONException: Expected ':' after top_id at character 1253 of [{"top_id":6,"top_url":
我认为这是模拟器的内存问题。它的基本内存是 1024。增加这个数量并没有改变任何东西。 任何关于问题背后原因的提示将不胜感激。另外,如果您认为有改进的余地,请随时评论我的代码。 :)
真奇怪。
我可以想到两件事来尝试:
- 检查服务器的编码和String构造函数的编码。
服务器可能使用 Latin-1 (ISO-8859-1) 进行解码,而字符串使用 UTF-8 进行编码。但是 JSON 应该以 Unicode 发送,而 Android 的默认字符集是 UTF-8。检查 HTTP Content-type 响应头;它应该说:application/json; charset=utf-8
。如果 charset
部分不存在,请进行一些调查并找出您的服务器用于解码为 HTTP 流的字符集。并检查 phone 和模拟器上的默认字符集是否相同;它应该是UTF-8。
- 在读取数据之后构造字符串之前,尝试在 ByteArrayOutputStream 上调用
flush()
。
可能 phone OS 和模拟器 OS 在流数据 transferred/buffered/flushed.
上存在细微差别如果 flush()
不起作用,请尝试在不使用 ByteArrayOutputStream 的情况下重写代码。例如,您可以用 InputStreamReader
包装输入流,它读取字符而不是字节,然后使用 StringBuilder
或 StringBuffer
.
使代码更好的一种方法是使用 JSONReader
而不是 JSONArray
或 JSONObject
。 JSONReader
将包装一个 InputStreamReader
,后者又包装 HTTP 输入流。它可以更快并且更有效地存储内存,因为您不必在开始解析数据之前读取整个输入流。当服务器发送大量 JSON 数据时,情况会大不相同。
您应该检查 is.read()
的 return 值。变化
while ( is.read(b) != -1)
baos.write(b);
至
int nread;
while ( (nread=is.read(b)) != -1)
baos.write(b, 0, nread);