9
votes

Java / Android: java.lang.outofMemoryError lors de la construction d'un objet JSON

Je importe des données JSON à partir d'une base de données publique URI http://data.seattle.gov /api/views/3k2p-39jp/rows.json et les lignes vont jusqu'à 445454. Utilisation du code suivant, je construisons l'objet JSON de l'ensemble des données.

   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");


1 commentaires

Lisez des parties de celui-ci au lieu de tout.


4 Réponses :


1
votes

Si possible uniquement des pièces des données - cela réduit également l'heure du réseau IO et permet ainsi de sauvegarder la batterie.

Sinon, vous pourriez essayer de ne pas conserver les données entrantes en mémoire, mais pour "diffuser" sur la carte SD. Quand il est stocké là-bas, vous pouvez ensuite itérer sur elle. Très probablement, cela signifiera utiliser votre propre tokéniseur JSON qui ne construit pas d'arbre complet, mais qui est capable de (comme un analyseur saxo), regardez uniquement une partie de l'arborescence d'objets à la fois.

Vous pouvez consulter Jackson , qui a un mode de diffusion en continu, qui peut être applicable. < / p>


0 commentaires

5
votes

que JSON est énorme!

Vous devez absolument utiliser un analyseur JSON Streaming JSON. Il y en a deux pour Android: GSON et Jackson.

Streaming GSON est expliqué à: https://sites.google.com/site/gson/ Streaming

J'aime comment GSON explique le problème que vous avez:

La plupart des applications doivent utiliser uniquement l'API du modèle d'objet. Le streaming JSON est utile en quelques situations:

Quand il est impossible ou indésirable de charger le modèle d'objet entier dans la mémoire. Ceci est le plus pertinent sur les plates-formes mobiles où la mémoire est limitée.

Jackson Streaming est documenté à: http://wiki.fasterxml.com/jacksoninfiveminutes#streaming_api_example


2 commentaires

J'aime le gson. Donc, vous dites au lieu d'utiliser bufferedreader et stringbuilder Je devrais faire jsonreader et list pour avoir un avantage sur des problèmes de mémoire?


Correct. JSONReader prendra dans votre Inverstream afin de remplacer à la fois BufferedReader et StringBuilder dans votre code. Notez que le message est un exemple de classe. En regardant ce Json, vous voudrez probablement remplacer cela avec votre propre classe de policole. Étant donné que le Json n'est pas simplement un grand tableau comme dans les exemples, vous devrez aborder le tableau contenant d'abord les réponses de la police, puis vous pouvez commencer à itérifier à travers ce tableau.



1
votes

L'analyseur de pull en streaming est le chemin. Je recommande GSON, car cela dispose d'une petite pièce de repos à mémoire (juste tirer à l'analyse est d'environ 16k, Jackson est beaucoup plus gros)

Votre code est problématique parce que vous allouez:

  • tampon pour contenir toutes les données de chaîne provenant du service
  • Tous les objets JSON DOM

    Et ceci est lent et vous donne une masse de mémoire.

    Si vous avez besoin d'objets Java hors de vos données JSON, vous pouvez essayer mon petit bâtiment de la bibliothèque de base de données sur GSON (Shameles auto-publicité):

    https://github.com/ko5tik/jsonSerializer


0 commentaires

0
votes

Je l'ai fait un peu différemment, mon code JSON attendait le statut, qui vient vers la fin. J'ai donc modifié le code pour revenir plus tôt.

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


0 commentaires