2016-01-26 4 views
10

Ich mache eine Android-App, die einen ASP.NET WebService ausführt. Webservice sendet ein JSON-Objekt, und die App analysiert das Objekt und zeigt es auf dem Bildschirm an. In einem Fall ist das JSON-Objekt zu groß und ich erhalte den Fehler "Fehler bei der Binder-Transaktion". Meine Lösung besteht darin, das JSON-Objekt abzurufen und es in den App-Code einzubetten, damit das JSON-Objekt nicht vom Server abgerufen werden muss. Können Sie mir andere Dinge sagen, die ich für dieses Problem tun kann? Oder können Sie mir sagen, wie man dieses JSON-Objekt vom Webservice bekommt? Vielen Dank.Wie man mit einem großen JSON-Objekt unter Android umgehen kann

+1

Können Sie angeben, wie groß ist es? wie über xxx Mb? Laden Sie den gesamten JSON herunter und das Parsen kann teuer sein. – sakiM

+0

Warum holen Sie es von einem Server und warum speichern Sie es als JSON, wenn es statisch ist und in der App versendet werden kann? – rds

+0

Dieses Problem ist nicht wegen der JSON-Datei, es gibt etwas anderes, das Sie übersehen. Sie sollten logcat-Ausgabe anhängen, wenn Sie eine Lösung wünschen. – chandil03

Antwort

8

Senden Sie die große Größe Daten vom Server an die mobile. JSON ist leicht. Wenn Sie die Daten auf effizientere Weise übergeben möchten, übergeben Sie sie in Paginierung. Wenn Sie mehr leichter Protokoll als JSON verwenden möchten dann implementieren Sie die unten Google-Protokoll, die wirklich nützlich sind, die wichtigsten Sprachen unterstützen. Im Folgenden sind kleinere Serialized Datenstruktur. Google-Datenaustauschprotokoll.

1.Google Protocol

2.Flat Buffers

3.Nano-proto buffers

Hope dies nützlich Sie sein.

4

Wenn die Daten groß sind, versuchen Sie, sie in der Datenbank zu speichern, und bearbeiten Sie sie dann mit SQLite. (aber nicht empfohlen, wenn seine Dynamik)

Um Json-Objekt zu analysieren, verwenden Sie Gson oder Jackson. Dies wird dazu beitragen, den Speicherverbrauch erheblich zu reduzieren, da die JSON-Daten teilweise analysiert werden. erhalten Gson, jackson hier https://sites.google.com/site/gson/gson-user-guide http://jackson.codehaus.org/

A jackson Beispiel http://www.mkyong.com/java/jackson-streaming-api-to-read-and-write-json/

+1

Ich würde Jackson über GSON empfehlen. In meinen Tests, bei denen ein sehr großes JSON-Objekt von einem InputStream analysiert wird, ist Ersteres etwa 25% schneller und benötigt weniger Speicher. –

0

Sie könnten Ihre JSON in Ihrer App-Code einbetten, wie Sie vorgeschlagen, aber das wird ein schlechter Ansatz, wenn die JSON dynamisch ist. Dann müssten Sie ein Update für Ihre App durchführen, sobald sich der JSON ändert.

Eine bessere Lösung wäre das Paginieren des von Ihrem WebService generierten JSON, d. H. Das Brechen des JSON in kleinere Teile, die Sie nacheinander in separaten API-Aufrufen abrufen können.

+0

Das Problem ist, dass ich den großen JSON vom Webservice nicht bekommen kann. Kannst du mir sagen, wie ich ihn bekomme? Vielen Dank. – jason

+0

Die Streaming API von GSON oder Jackson Libraries ist eine gute Option, wie in anderen Antworten in diesem Post vorgeschlagen. Sie sollten dies jedoch nur tun, wenn Sie die Ausgabe Ihres WebService nicht ändern können. Es wäre besser, zuerst die Ausgabe von WebService abzubrechen. Wenn Sie das nicht können, gehen Sie zur Streaming-API. –

2

Die erste Sache: Wenn es einen Absturz oder eine Ausnahme in Ihrem Code gibt, möchten Sie wahrscheinlich das posten. "Failed Binder Exception" ist ein bisschen zu vage, um zu verstehen, was Sie tun.

Wenn Sie Ihre Android App wirklich mit eingebettetem JSON versenden möchten (damit Sie sie nicht von einem Server abrufen müssen, sollten Sie sie als Asset speichern und mit AssetManager darauf zugreifen. Sie legen die Datei im Grunde mit dem json in Wenn Sie es immer noch vom Server herunterladen und darauf reagieren möchten, sollten Sie Streaming-APIs verwenden, um den JSON herunterzuladen und zu parsen. Das JSONObject von Android tut das nicht und besteht darauf, dass Sie es mit AssetManager auslesen wenn Sie die gesamte JSON-Zeichenfolge im Speicher haben, bevor sie geparst werden kann

Wenn Sie direkt von einem URL-Download in einen Streaming-Parser streamen möchten (z s GSON), versuche etwas in dieser Richtung. Zuerst einen Inputstream aus der URL erhalten Sie zu holen sind versuchen:

URL u = new URL(url); 
    URLConnection conn = u.openConnection(); 
    InputStream is = new BufferedInputStream(conn.getInputStream()); 

Dann füttern die Input direkt auf Ihrem Streaming-Parser. Dies sollte die Notwendigkeit verhindern, dass die gesamte Antwort in den Speicher zu ziehen, bevor das Parsen, aber Sie müssen noch genügend Speicher, alle Objekte enthalten, die der Parser erstellt:

GsonBuilder gb = new GsonBuilder(); // configure this as necessary 
    Gson gson = gb.create(); 
    final Result response = gson.fromJson(
     new InputStreamReader(is, Charset.forName("UTF-8")), 
     Result.class 
    ); 

„Ergebnis“ hier ist eine Klasse, die enthalten die Daten aus der JSON-Antwort. Sie müssen sicherstellen, dass alle Zuordnungen für Ihre Daten funktionieren. Lesen Sie also auf GSON nach und tun Sie, was in Ihrem Fall funktioniert.

Sie können GSON auch verwenden, um die JSON-Daten zu analysieren, wenn Sie sie in einem Asset speichern. Geben Sie einfach den InputStream der Asset-Daten und es funktioniert auf die gleiche Weise.

0

Vorzugsweise versuchen, das JSON-Objekt zu kleinerem Objekt zu brechen und von webService erhalten,

oder Daten in Teilen erhalten und wenn u cant tun

Sie haben einen Streaming-JSON-Parser zu verwenden. https://sites.google.com/site/gson/streaming

Ich persönlich mag Gson:

  1. Gson

  2. Jackson

Gson Streaming bei erklärt: Für Android u kann diese 2 verwenden.

0

Die folgende Klasse ApiUrlClass.java verfügt über alle Methoden, die Sie benötigen. Bitte lies die Kommentare der Klasse, die ich geschrieben habe. Das wird Ihnen helfen, das zu tun, was Sie benötigen. Dies nutzt auch transparent.

import android.graphics.Bitmap; 
import android.net.Uri; 
import android.os.Build; 
import android.util.Log; 
import org.apache.http.entity.mime.HttpMultipartMode; 
import org.apache.http.entity.mime.content.ByteArrayBody; 
import org.apache.http.entity.mime.content.ContentBody; 
import org.apache.http.entity.mime.content.StringBody; 
import org.json.JSONArray; 
import org.json.JSONException; 
import org.json.JSONObject; 

import java.io.BufferedReader; 
import java.io.BufferedWriter; 
import java.io.ByteArrayOutputStream; 
import java.io.FileNotFoundException; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.OutputStream; 
import java.io.OutputStreamWriter; 
import java.net.HttpURLConnection; 
import java.net.SocketTimeoutException; 
import java.net.URL; 
import java.net.UnknownHostException; 

import javax.net.ssl.HttpsURLConnection; 
import javax.net.ssl.SSLPeerUnverifiedException; 

/* 
Usage of the class 

Create all the necessary API Call methods you need. 
And either use a Thread or AsyncTask to call the following. 

    JSONObject response = ApiUrlCalls.login("username", "passowrd"); 

After the response is obtained, check for status code like 

    if(response.getInt("status_code") == 200){ 
     //TODO: code something 
    } else { 
     //TODO: code something 
    } 
*/ 

public class ApiUrlCalls { 

    private String HOST = "https://domain/path/"; //This will be concated with the function needed. Ref:1 

    /* 
     Now utilizing the method is so simple. Lets consider a login function, which sends username and password. 
     See below for example. 
    */ 

    public static JSONObject login(String username, String password){ 

     String functionCall = "login"; 
     Uri.Builder builder = new Uri.Builder() 
       .appendQueryParameter("username", username) 
       .appendQueryParameter("password", password); 

     /* 
      The return calls the apiPost method for processing. 
      Make sure this should't happen in the UI thread, orelse, NetworkOnMainThread exception will be thrown. 
     */ 
     return apiPost(builder, functionCall); 

    } 

    /* 
     This method is the one which performs POST operation. If you need GET, just change it 
     in like Connection.setRequestMethod("GET") 
    */ 
    private static JSONObject apiPost(Uri.Builder builder, String function){ 
     try { 
      int TIMEOUT = 15000; 
      JSONObject jsonObject = new JSONObject(); 
      try { 
       URL url = null; 
       String response = ""; 

       /* 
        Ref:1 
        As mentioned, here below, in case the function is "login", 
        url looks like https://domain/path/login 

        This is generally a rewrited form by .htaccess in server. 
        If you need knowledge on RESTful API in PHP, refer 
        http://stackoverflow.com/questions/34997738/creating-restful-api-what-kind-of-headers-should-be-put-out-before-the-response/35000332#35000332 

        I have answered how to create a RESTful API. It matches the above URL format, it also includes the .htaccess 
       */ 

       url = new URL(HOST + function); 

       HttpsURLConnection conn = null; 
       conn = (HttpsURLConnection) url.openConnection(); 
       assert conn != null; 
       conn.setReadTimeout(TIMEOUT); 
       conn.setConnectTimeout(TIMEOUT); 
       conn.setRequestMethod("POST"); 
       conn.setDoInput(true); 
       conn.setDoOutput(true); 

       String query = builder.build().getEncodedQuery(); 

       OutputStream os = conn.getOutputStream(); 
       BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8")); 
       writer.write(query); 
       writer.flush(); 
       writer.close(); 
       os.close(); 
       conn.connect(); 


       int responseCode = conn.getResponseCode(); 
       String responseMessage = conn.getResponseMessage(); 
       jsonObject.put("status_code", responseCode); 
       jsonObject.put("status_message", responseMessage); 

       /*The if condition below will check if status code is greater than 400 and sets error status 
       even before trying to read content, because HttpUrlConnection classes will throw exceptions 
       for status codes 4xx and 5xx. You cannot read content for status codes 4xx and 5xx in HttpUrlConnection 
       classes. 
       */ 

       if (jsonObject.getInt("status_code") >= 400) { 
        jsonObject.put("status", "Error"); 
        jsonObject.put("msg", "Something is not good. Try again later."); 
        return jsonObject; 
       } 

       String line; 
       BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); 

       while ((line = br.readLine()) != null) { 
        response += line; 
       } 
       //Log.d("RESP", response); 

       /* 
        After the actual payload is read as a string, it is time to change it into JSON. 
        Simply when it starts with "[" it should be a JSON array and when it starts with "{" 
        it is a JSONObject. That is what hapenning below. 
       */ 
       if(response.startsWith("[")) { 
        jsonObject.put("content", new JSONArray(response)); 
       } 
       if(response.startsWith("{")){ 
        jsonObject.put("content", new JSONObject(response)); 
       } 


      } catch(UnknownHostException e) { 
      //No explanation needed :) 
       jsonObject.put("status", "UnknownHostException"); 
       jsonObject.put("msg", "Check your internet connection"); 
      } catch (SocketTimeoutException){ 
      //This is when the connection timeouts. Timeouts can be modified by TIMEOUT variable above. 
       jsonObject.put("status", "Timeout"); 
       jsonObject.put("msg", "Check your internet connection"); 
      } catch (SSLPeerUnverifiedException se) { 
      //When an untrusted SSL Certificate is received, this happens. (Only for https.) 
       jsonObject.put("status", "SSLException"); 
       jsonObject.put("msg", "Unable to establish secure connection."); 
       se.printStackTrace(); 
      } catch (IOException e) { 
      //This generally happens when there is a trouble in connection 
       jsonObject.put("status", "IOException"); 
       jsonObject.put("msg", "Check your internet connection"); 
       e.printStackTrace(); 
      } catch(FileNotFoundException e){ 
      //There is no chance that this catch block will execute as we already checked for 4xx errors 
       jsonObject.put("status", "FileNotFoundException"); 
       jsonObject.put("msg", "Some 4xx Error"); 
       e.printStackTrace(); 
      } catch (JSONException e){ 
      //This happens when there is a troble reading the content, or some notice or warnings in content, 
      //which generally happens while we modify the server side files. Read the "msg", and it is clear now :) 
       jsonObject.put("status", "JSONException"); 
       jsonObject.put("msg", "We are experiencing a glitch, try back in sometime."); 
       e.printStackTrace(); 
      } return jsonObject; 

     } catch (JSONException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

} 
1

Übermitteln Sie Daten zwischen Aktivitäten? Ich meine, versuchen Sie, das große Datenobjekt (erhalten von der WS) zu einer anderen Aktivität mit intent.putExtra() zu übergeben?

+0

Ja, das mache ich. Eigentlich stürzt die App genau an diesem Punkt ab. – jason

+1

Dann wahrscheinlich, weil es eine Grenze zwischen der Größe der Daten gibt, die Sie über eine Absicht weitergeben können. Versuchen Sie, die Daten in einer Datei zu speichern und übergeben Sie den Dateipfad dann über die Absicht. Verwenden Sie bei der nächsten Aktivität den empfangenen Dateipfad, um einen Verweis auf die gespeicherte Datei zu erhalten. –

Verwandte Themen