Ich muss eine Menge Daten aus einer SQLite-Datenbank lesen und erstellen Sie eine ordnungsgemäß formatierte JSON.Android riesige JSONObject toString geht OutOfMemoryError
Ich erreiche dies zur Zeit durch ein Objekt namens RequestPayload
, das einige ArrayList
s enthält, in denen ich die Daten, die ich von SQLite gelesen habe.
Die RequestPayload
Klasse hat eine parseJson()
Methode, die eine JSONObject
, auf dem zurückgibt ich die toString()
Methode schließlich nennen meine JSON String zu erhalten, die schließlich auf eine Datei geschrieben wurde.
Jetzt, wenn ich "kleine" Datenmengen in SQLite habe, geht alles gut. Wenn ich eine Menge Daten haben, ist das, was passiert:
06-28 09:55:34.121 10857-6799/it.example.sampler E/AndroidRuntime: FATAL EXCEPTION: Thread-195240
Process: it.example.sampler, PID: 10857
Theme: themes:{com.cyanogenmod.trebuchet=overlay:system, com.android.settings=overlay:system, default=overlay:system, iconPack:system, fontPkg:system, com.android.systemui=overlay:system, com.android.systemui.navbar=overlay:system}
java.lang.OutOfMemoryError: Failed to allocate a 52962812 byte allocation with 16764752 free bytes and 41MB until OOM
at java.lang.StringFactory.newStringFromChars(Native Method)
at java.lang.AbstractStringBuilder.toString(AbstractStringBuilder.java:629)
at java.lang.StringBuilder.toString(StringBuilder.java:663)
at org.json.JSONStringer.toString(JSONStringer.java:430)
at org.json.JSONObject.toString(JSONObject.java:690)
at it.example.sampler.controllers.network.RequestBodyEncoder.serialise(RequestBodyEncoder.java:69)
at it.example.sampler.controllers.network.RequestBodyEncoder.createPacket(RequestBodyEncoder.java:50)
at it.example.sampler.services.FileStoreRunnable.run(FileStoreRunnable.java:57)
at java.lang.Thread.run(Thread.java:818)
06-28 09:55:34.509 10857-10857/it.example.sampler E/WindowManager: android.view.WindowLeaked: Activity it.example.sampler.ui.StartSamplingActivity has leaked window com.android.internal.policy.PhoneWindow$DecorView{74710d V.E...... R......D 0,0-1026,494} that was originally added here
at android.view.ViewRootImpl.<init>(ViewRootImpl.java:372)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:299)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:86)
at android.app.Dialog.show(Dialog.java:319)
at it.example.sampler.ui.StartSamplingActivity.executeStop(StartSamplingActivity.java:305)
at it.example.sampler.ui.StartSamplingActivity.onClickedButton(StartSamplingActivity.java:256)
at it.example.sampler.ui.StartSamplingActivity$3.onClick(StartSamplingActivity.java:190)
at android.view.View.performClick(View.java:5204)
at android.view.View$PerformClick.run(View.java:21158)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5461)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
der Code Jetzt:
die Fehlerzeile aus dieser Methode ist:
private String serialise() throws JSONException {
// Serialise
String sampleString = mPayload.parseJSON().toString(); // THIS LINE
Logger.get().d(LOG_TAG, "Serialised payload: -> " + sampleString);
return sampleString;
}
und wenn bekam ich die LogCat korrekt ist der Fehler während der Ausführung der toString()
Methode und es scheint, dass das JSON-Objekt zu groß ist.
Wie kann ich mit dieser Situation umgehen?
UPDATE: beantworten zu @YashJain Kommentar für die Größe des JSONObject zu fragen.
Nachdem eine Abtastung Abtastung dauerte 2 Stunden, die ich eine JSON hatte enthält:
- JSONArray enthält 155,432
float
s - JSONArray enthaltend 8.393
float
s - JSONArray enthaltend 8.393 benutzerdefiniertes Objekt mit 5
float
s jeder (und ein String) ,432
int
s
In Bezug auf die Bytes enthalten
(12 * 155432 * 4) + (2 * 8393 * 4) + (1 * 8393 * 5) + (1 * 155432 * 4) ~= 8.191.573 bytes
UPDATE: Ich wurde nach dem verwendeten Komprimierungsalgorithmus gefragt. Ich benutze ZLIB
über die Java-Klassen Deflater
und DeflaterOutputStream
.
So ist die Strömung:
- Beispieldaten -> Speichern Sie sie in
SQLite
- Lesen von
SQLite
-> BuildRequestPayload
Objekt im Speicher - konvertieren
RequestPayload
ObjektJSONObject
(mit benutzerdefinierten eine benutzerdefinierte Parser). - umrechnen
JSONObject
zu String (mitJSONObject
toString()
Methode) - das String-Bytes komprimiert (mit
getBytes()
) -> kodieren sie in Base64 - Server
EDIT final Base64 String senden: Um auf die "mögliche doppelte Flagge" zu antworten, habe ich diese Frage während meiner Recherchen übrigens nicht gesehen, die mir nicht geholfen hat, weil sie largeHeap
Direktive benutzt (die ich nicht verwende). Auch gibt es keine akzeptierte Antwort und die einzige Antwort bietet keine praktische Lösung.
Mögliche Duplikate von [JSONObject.toString() gibt OutOfMemoryError] (http://stackoverflow.com/questions/32919833/jsonobject-tostring-returns-outofmemoryerror) – mdDroid
Ich weiß nicht die Antwort, aber ich will wissen, wie große Daten es halten kann? Wie viele Bytes/Zeichen. –
@mdDroid Ich habe eine Bearbeitung hinzugefügt, die erklärt, warum ich nicht die "possible duplicate" -Flag könnte helfen .. trotzdem danke für die Markierung, weil ich es nicht bei der Recherche vor der Frage zu sehen .. leider nicht Hilfe – FredMaggiowski