2012-03-21 7 views
8

Estoy importando los datos JSON a partir de una base de datos pública URI http://data.seattle.gov/api/views/3k2p-39jp/rows.json y las filas ir tan lejos como 445454. Usando el siguiente código estoy construyendo el objeto JSON de la totalidad datos.Java/Android: java.lang.OutOfMemoryError mientras que la construcción de un objeto 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"); 

Debido a que los datos son demasiado grandes, que estoy recibiendo 03-21 03:41:49.714: E/AndroidRuntime(666): Caused by: java.lang.OutOfMemoryError señalando la fuente de error en buildr.append(line).append("\n"). ¿De todos modos puedo manejar grandes conjuntos de datos sin tener problemas de asignación de memoria?

+0

leer partes de ella en lugar de todo ..? – JoxTraex

Respuesta

5

¡Ese JSON es enorme!

Definitivamente debe utilizar un analizador JSON de transmisión. Hay dos para Android: GSON y Jackson.

GSON Streaming se explica en: https://sites.google.com/site/gson/streaming

me gusta cómo GSON explica el problema que está teniendo:

La mayoría de las aplicaciones deben utilizar únicamente el modelo de objetos de la API. La transmisión JSON es útil en algunas situaciones:

Cuando es imposible o no deseable cargar todo el modelo de objetos en la memoria. Esto es más relevante en plataformas móviles donde la memoria es limitada.

Jackson Streaming se documenta en: http://wiki.fasterxml.com/JacksonInFiveMinutes#Streaming_API_Example

+0

Me gusta el GSON. ¿Entonces estás diciendo que en lugar de usar 'BufferedReader' y' StringBuilder' debería hacer 'JSONReader' y' List 'para tener una ventaja sobre los problemas de memoria? – jmishra

+0

Correcto. JSONReader captará su inputStream, de modo que reemplazará tanto a BufferedReader como a StringBuilder en su código. Tenga en cuenta que Message es una clase de ejemplo. Si observa ese JSON, probablemente quiera reemplazarlo con su propia clase PoliceResponse. Dado que el JSON no es solo una gran matriz como en los ejemplos, primero tendrá que navegar hasta la matriz que contiene las respuestas de la policía, luego puede comenzar a iterar a través de esa matriz. – louielouie

1

Si es posible, solo solicite partes de los datos, esto también reduce el tiempo de la red y ahorra batería.

De lo contrario, podría tratar de no guardar los datos entrantes en la memoria, sino de "transmitirlos" a la tarjeta SD. Cuando está almacenado allí, puede iterar sobre él. Lo más probable es que esto signifique usar su propio tokenizador JSON que no construye un árbol completo, pero que es capaz (como un analizador SAX) de mirar solo una parte del árbol de objetos a la vez.

Puede echar un vistazo a Jackson, que tiene un modo de transmisión, que puede ser aplicable.

1

pull parser Streaming es el camino. Yo recomendaría GSON, ya que esto tiene un pequeño footpring memoria (análisis sólo tire se trata de 16K, Jackson es mucho más grande)

Su código es problemática debido a que asigne:

  • búfer para contener todos los datos de cadena procedentes de
  • servicio
  • todos los objetos JSON DOM

y esto es lento, y le da la fusión de memoria.

En caso de que necesite objetos Java fuera de sus datos JSON, puede intentar mi pequeño edificio de la biblioteca de enlace de datos en GSON (shameles publicidad de auto apagado):

https://github.com/ko5tik/jsonserializer

0

lo hice un poco diferente, Mi El código JSON estaba esperando el estado, que viene hacia el final. Así que modifiqué el código para regresar antes.

// 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; 
      }   
     } 
Cuestiones relacionadas