我从公共数据库URI http://data.seattle.gov/api/views/3k2p-39jp/rows.json导入JSON数据,行直到445454.使用以下代码我构建整个数据的JSON对象。
HttpGet get = new HttpGet(uri);
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(get);
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
StringBuilder builder=new StringBuilder();
for(String line=null;(line = reader.readLine()) != null;){
builder.append(line).append("\n");
}
JSONTokener jsonTokener=new JSONTokener(builder.toString());
JSONObject finalJson=new JSONObject(jsonTokener);
JSONArray data=finalJson.getJSONArray("data");
由于数据太大,我得03-21 03:41:49.714: E/AndroidRuntime(666): Caused by: java.lang.OutOfMemoryError
指出错误来源buildr.append(line).append("\n")
。无论如何我可以处理大型数据集而不会出现内存分配问题吗?
答案 0 :(得分:5)
JSON很大!
您肯定需要使用流式JSON解析器。 Android有两个版本:GSON和Jackson。
GSON Streaming在https://sites.google.com/site/gson/streaming
解释我喜欢GSON如何解释您遇到的问题:
大多数应用程序应仅使用对象模型API。 JSON流媒体在以下几种情况下非常有用:
当不可能或不希望将整个对象模型加载到内存中时。这在内存有限的移动平台上最为相关。
Jackson Streaming记录于:http://wiki.fasterxml.com/JacksonInFiveMinutes#Streaming_API_Example
答案 1 :(得分:1)
如果可能,只请求部分数据 - 这也减少了网络的时间,从而节省了电池。
否则,您可能会尝试不将传入的数据保留在内存中,而是将其“流式传输”到SD卡上。当它存储在那里时,你可以迭代它。很可能这意味着使用您自己的JSON标记生成器,它不构建完整的树,但能够(如SAX解析器)一次只查看对象树的一部分。
您可以查看具有流式传输模式的Jackson,这可能适用。
答案 2 :(得分:1)
Streaming pull解析器就是这样。我推荐GSON,因为它有一个小内存footpring(只需拉解析约16K,杰克逊更大)
您的代码存在问题,因为您分配了:
这很慢,并且让你内存崩溃。
如果您需要JSON数据中的java对象,您可以尝试在GSON上构建我的小型数据绑定库(羞辱自我广告):
答案 3 :(得分:0)
我的做法有所不同,我的JSON代码正在等待状态,即将结束。所以我修改了代码以便早些时候返回。
// try to get formattedAddress without reading the entire JSON
String formattedAddress;
while ((read = in.read(buff)) != -1) {
jsonResults.append(buff, 0, read);
formattedAddress = ((String) ((JSONObject) new JSONObject(
jsonResults.toString()).getJSONArray("results").get(0))
.get("formatted_address"));
if (formattedAddress != null) {
Log.i("Taxeeta", "Saved memory, returned early from json") ;
return formattedAddress;
}
}
JSONObject statusObj = new JSONObject(jsonResults.toString());
String status = (String) (statusObj.optString("status"));
if (status.toLowerCase().equals("ok")) {
formattedAddress = ((String) ((JSONObject) new JSONObject(
jsonResults.toString()).getJSONArray("results").get(0))
.get("formatted_address"));
if (formattedAddress != null) {
Log.w("Taxeeta", "Did not saved memory, returned late from json") ;
return formattedAddress;
}
}