Java/Android:Java.lang.OutOfMemoryError在构建JSON对象时出错

Java/Android:Java.lang.OutOfMemoryError在构建JSON对象时出错,java,android,json,webrequest,Java,Android,Json,Webrequest,我正在从一个公共数据库URI导入JSON数据,行数达到445454行。使用下面的代码,我正在构建整个数据的JSON对象 HttpGet get = new HttpGet(uri); HttpClient client = new DefaultHttpClient(); HttpResponse response = client.execute(get); BufferedReader reader = new BufferedReader(new InputStre

我正在从一个公共数据库URI导入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):原因是:java.lang.OutOfMemoryError
将错误源指向
buildr.append(line).append(“\n”)
。我是否可以处理大型数据集而不出现内存分配问题?

如果可能,只请求部分数据-这也减少了网络io的时间,从而节省了电池

否则,您可以尝试不将传入的数据保存在内存中,而是将其“流”到sd卡上。当它存储在那里时,您可以对其进行迭代。这很可能意味着使用您自己的JSON标记器,它不构建完整的树,但能够(像SAX解析器一样)一次只查看对象树的一部分

您可以看看,它有一个流模式,这可能是适用的。

JSON是巨大的

您肯定需要使用流式JSON解析器。Android有两种:GSON和Jackson

GSON流媒体的解释如下:

我喜欢GSON如何解释您遇到的问题:

大多数应用程序应该只使用对象模型API。JSON流在以下几种情况下非常有用:

当无法或不希望将整个对象模型加载到内存中时。这在内存有限的移动平台上最为相关


Jackson流媒体记录在:

流媒体拉式解析器就是一种方式。我建议使用GSON,因为它的内存占用空间很小(仅拉动解析大约为16K,jackson要大得多)

您的代码有问题,因为您分配了:

  • 用于保存来自服务的所有字符串数据的缓冲区
  • 所有JSON DOM对象
这很慢,会让你的记忆崩溃

如果您需要JSON数据中的java对象,可以尝试在GSON上构建我的小型数据绑定库(shameles self advertising off):


我的做法有点不同,我的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;
            }           
        } 

阅读其中的一部分而不是全部?我喜欢GSON。所以你是说,我不应该使用
BufferedReader
StringBuilder
而应该使用
JSONReader
List
来克服内存问题?正确。JSONReader将接收您的inputStream,以便在代码中同时替换BufferedReader和StringBuilder。注意,Message是一个示例类。看看这个JSON,您可能想用自己的policResponse类来代替它。由于JSON不像示例中那样只是一个大数组,因此必须首先导航到包含警方响应的数组,然后才能开始遍历该数组。