Sehr große SOAP-Antwort – Android – Fehler aufgrund unzureichenden Arbeitsspeichers
Lesezeit: 5 Minuten
Ich habe eine Anwendung, bei der ich eine große Datenmenge über einen SOAP-Aufruf an einen Webservice in die Anwendung herunterladen muss, wenn sie zum ersten Mal ausgeführt wird. Die Antwort wird dann an eine Funktion gesendet, die das XML konvertiert und die Daten in einer db-Datei speichert.
Die Daten sind mehr als 16 MB groß und ich habe jedes Mal einen java.lang.OutOfMemoryError.
Eine Änderung des Webservices zur Ausgabe kleinerer Datenmengen ist keine Option.
Gibt es eine Möglichkeit, große Datenmengen herunterzuladen? So etwas wie ein InputStream vielleicht?
Kann jemand vorschlagen, was in diesem Fall zu tun ist?
Danke und Grüße Mukul
Ich denke, vtd-xml kann zweifellos dazu beitragen, die Speichernutzung zu senken.
– vtd-xml-Autor
13. März 11 um 08:06 Uhr
Mukul Jain
Nur ein Update, ich habe festgestellt, dass der “call” -Methode in AndroidHttpTransport in dieser Zeile der Speicher ausgeht –
if (debug) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buf = new byte[256];
while (true) {
int rd = is.read(buf, 0, 256);
if (rd == -1)
break;
bos.write(buf, 0, rd);
}
bos.flush();
buf = bos.toByteArray(); //Goes out of memory here
responseDump = new String(buf);
is.close();
is = new ByteArrayInputStream(buf);
Der Aufruf von toByteArray benötigt viel Speicher, um dies zu umgehen, schreibe ich die Antwort jetzt direkt in eine XML-Datei, anstatt sie in ein Byte-Array umzuwandeln, und diese wird an einem Ort meiner Wahl gespeichert. Hier –
if (debug) {
FileOutputStream bos = new FileOutputStream("/data/data/com.mypackage.myapp/response.xml");
byte[] buf = new byte[1048576];
int current = 0; int i=0; int newCurrent = 0;
while ((current = inputStream.read(buf)) != -1) {
newCurrent = newCurrent + current;
Log.d("current", "Current = " + current + " total = "+newCurrent+" i = "+i++);
bos.write(buf, 0, current);
}
bos.flush();
}
Dem Gerät geht nicht mehr der Arbeitsspeicher aus, und ich habe eine benutzerdefinierte Parsing-Methode, die dieses XML nimmt und in die DB schreibt.
Wie hast du das mit dem verwendet SoapObject in dem SoapSerializationEnvelope? Können Sie Ihr gesamtes Beispiel zeigen, indem Sie den Webdienst mit ksoap2 aufrufen und die Ergebnisse in eine Datei schreiben, anstatt sie in a SoapObject?
– Sarah Gefäße
6. Oktober 11 um 13:42 Uhr
Danke Mukul für deine Antwort. Es ist jedoch nicht klar, wie du die Antwort erhalten hast. Kannst du bitte deine gesamte Methode angeben, um die Antwort zu erhalten und in einer Datei zu speichern?
– Raj
3. Juli 13 um 6:35 Uhr
@Octavian Damiean Ich habe denselben Code verwendet und dann nie eine OutOfMemory-Ausnahme erhalten, aber ich bekomme jetzt org.xmlpull.v1.XmlPullParserException: unerwarteter Typ (Position:END_DOCUMENT null@1:1 in java.io.InputStreamReader@2fe6cc09) Ihre Hilfe wird für mich wie ein Diamant sein..
– Arju
17. November 16 um 12:34 Uhr
Zwei Strategien zur Lösung dieses Problems:
Speichern Sie Ihren SOAP-XML-Stream beim Herunterladen direkt auf der Festplatte. Speichern Sie es nicht im Gedächtnis.
Analysieren Sie es mit einem Parser im SAX-Stil, bei dem Sie nicht das gesamte DOM in den Speicher laden, sondern es in Blöcken parsen.
Abhängig von der Art von XML, mit der Sie arbeiten, ist die Verwendung von SAX-Parsern im Code normalerweise schwieriger. Sie müssen viele Dinge selbst im Auge behalten und können nicht von Abschnitt zu Abschnitt Ihres DOM-Baums “springen”. Aber der Speicherverbrauch wird viel geringer sein.
Beachten Sie jedoch, dass viele “High-Level”-Netzwerkkommunikationsbibliotheken normalerweise das gesamte XML-DOM in den Speicher laden, was hier der Fall sein könnte. Wahrscheinlich müssen Sie die HTTP-Verbindung selbst erstellen und verwalten und das Ergebnis dann manuell parsen.
Hallo Adrian, danke für die Antwort, ich habe das ausprobiert und es funktioniert gut, in diesem Fall ist die XML-Datei selbst etwa 8 MB groß. Bitte sehen Sie sich meine Antwort unten an, ich habe den Code auch eingefügt, um dies für die Zukunft zu tun
– Mukul Jain
13. Februar 11 um 10:37 Uhr
Fest!
Ich habe die Java-Klasse HttpTransportSE von hier heruntergeladen/kopiert (nach dem Kopieren können einige Codefehler auftreten, die jedoch alle schnell behoben werden können) und zu meinem Paket hinzugefügt:
diese Zeile aus meiner Verbindungsklasse entfernt:
import org.ksoap2.transport.HttpsTransportSE;
und ersetzte diesen Code in meiner neuen HttpTransportSE.java-Datei:
if (debug) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buf = new byte[256];
while (true) {
int rd = is.read(buf, 0, 256);
if (rd == -1)
break;
bos.write(buf, 0, rd);
}
bos.flush();
buf = bos.toByteArray(); //Goes out of memory here
responseDump = new String(buf);
is.close();
is = new ByteArrayInputStream(buf);
}
mit diesem
if (debug) {
FileOutputStream bos = new FileOutputStream(file);
byte[] buf = new byte[256];
while (true) {
int rd = is.read(buf, 0, 256);
if (rd == -1) {
break;
}
bos.write(buf, 0, rd);
}
bos.flush();
}
wobei „file“ ein einfaches Dateiobjekt wie beispielsweise new File(“/sdcard/“, „myFile.xml“) ist
Ich habe dies in ksoap2-android 3.0.0-RC.5-SNAPSHOT implementiert. Könnten Sie bitte versuchen, ob es für Sie funktioniert?
– Manfred Moser
12. November 12 um 19:38 Uhr
Ok, ich werde versuchen, das Ergebnis so schnell wie möglich zu posten
– Königshomer
13. November 12 um 18:05 Uhr
@kinghomer Ich habe denselben Code verwendet und dann nie eine OutOfMemory-Ausnahme erhalten, aber ich bekomme jetzt org.xmlpull.v1.XmlPullParserException: unerwarteter Typ (Position: END_DOCUMENT null@1:1 in java.io.InputStreamReader@2fe6cc09) Ihre Hilfe wird Sei wie ein Diamant für mich..
– Arju
17. November 16 um 12:35 Uhr
.
5020200cookie-checkSehr große SOAP-Antwort – Android – Fehler aufgrund unzureichenden Arbeitsspeichersyes
Ich denke, vtd-xml kann zweifellos dazu beitragen, die Speichernutzung zu senken.
– vtd-xml-Autor
13. März 11 um 08:06 Uhr