Android:错误解析有限内存(特定)设备上的大Json

时间:2016-07-05 22:11:48

标签: android json

使用OkHttpClient在TC75(8mb RAM)上解析36972行JSON响应时,我得到了java.lang.OutOfMemoryError。当我尝试调用response.body()。string()

时会出现问题
E/dalvikvm-heap: Out of memory on a 26525298-byte allocation.

我试图将数据保存在StringBuilder和流式JsonReader中[在此答案中]。[1]

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(...).build();

try {
    Response response = client.newCall(request).execute();
    JsonReader jsonReader = new JsonReader(new StringReader(response.body().string()));

    ... (loads of JsonReader parsing)
} catch (IOException | ParseException e) {
    e.printStackTrace();
}

在Samsung S6 Active(3GB内存)上运行时,应用程序可以轻松解析此JSON。如何通过如此有限的RAM避免内存不足错误?它甚至可能吗?

堆栈跟踪:

E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #2
   Process: com.at.project, PID: 4409
   java.lang.RuntimeException: An error occured while executing doInBackground()
      at android.os.AsyncTask$3.done(AsyncTask.java:300)
      at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
      at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
      at java.util.concurrent.FutureTask.run(FutureTask.java:242)
      at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
      at java.lang.Thread.run(Thread.java:841)
   Caused by: java.lang.OutOfMemoryError
      at java.lang.String.<init>(String.java:255)
      at java.lang.String.<init>(String.java:228)
      at com.squareup.okhttp.ResponseBody.string(ResponseBody.java:83)
      at com.at.project.activities.LoginNewActivity$UserLoginTask.getOEMPartPricingJson(LoginNewActivity.java:1496)
      at com.at.project.activities.LoginNewActivity$UserLoginTask.downloadAnyNewJson(LoginNewActivity.java:860)
      at com.at.project.activities.LoginNewActivity$UserLoginTask.checkForatDprojectdates(LoginNewActivity.java:746)
      at com.at.project.activities.LoginNewActivity$UserLoginTask.checkForUpdates(LoginNewActivity.java:659)
      at com.at.project.activities.LoginNewActivity$UserLoginTask.doInBackground(LoginNewActivity.java:486)
      at com.at.project.activities.LoginNewActivity$UserLoginTask.doInBackground(LoginNewActivity.java:465)
      at android.os.AsyncTask$2.call(AsyncTask.java:288)
      at java.util.concurrent.FutureTask.run(FutureTask.java:237)
      at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) 
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
      at java.lang.Thread.run(Thread.java:841)    

2 个答案:

答案 0 :(得分:0)

流式解析器设计用于返回XML或json等元素,因为它们是从数据流中解析出来的。它们通常允许用户解析总内存使用率较低的大型文档,或者在开始对正在解析的文件执行有用的操作之前减少缓冲时间。

Jackson Streaming解析器是用java编写的。它可能会做你需要的。我确信还有其他流媒体json解析器。

对于低内存系统,您可能无法将所有数据吸收到String或StringBuilder中。相反,您将把流传递给流解析器并在元素出现时处理回调。您需要抛弃未使用的和不必要的元素,而不是尝试构建完整json文件的解析树。

答案 1 :(得分:0)

内存错误与变量可以拥有的最大内存量有关。

我建议使用和JSON到POJO帮助程序,它将数据直接存储在具有更大内存堆的对象中。

使用GSONJackson库非常简单。

您还可以使用HTTP Helper更轻松地执行请求,其中大多数已经使用GSON和Jackson进行反序列化。

我使用Retrofit,但Volley也是一个不错的选择。

我知道不能解决您的错误,但我认为实现这些库比通过您自己的内存使用和http请求进行优化要容易得多。