2015-01-13 4 views
21

ich meine http Anrufe über die OkHttp Bibliothek implementieren. Alles funktioniert gut, aber ich bemerkte, dass, wenn ich den Körper als eine Zeichenfolge der Antwort zweimal zugreifen wird IllegalStateException geworfen werden. Das heißt, ich tun (zum Beispiel): Log.d("TAG", response.body().string()) und danach möchte ich eigentlich diese Zeichenfolge wie processResponse(response.body().string()) verwenden. Aber dieser zweite Aufruf löst die Ausnahme mit der Nachricht closed aus.Zugriff auf Körper Zeichenfolge eines OkHttp Antwort zweimal ergibt Illegal: geschlossen

Wie kann es möglich sein, dass in einem Ausfall einen String zweimal führt zugreifen? Ich möchte diese Antwort verarbeiten, ohne ein Wrapper/Dummy-Objekt hinzufügen zu müssen, nur um einige Werte zu speichern (wie Header, Body, Statuscode).

Antwort

25

Die string Verfahren auf die Reaktion wird das Eingangs (Netzwerk) Strom gelesen und in eine Zeichenfolge konvertiert. So wird die Zeichenfolge dynamisch erstellt und an Sie zurückgegeben. Beim zweiten Aufruf ist der Netzwerkdatenstrom bereits verbraucht und nicht mehr verfügbar.

Sie sollten das Ergebnis von string in ein String-Variable, speichern und sie dann so oft zugreifen, wie gebraucht.

+0

Ich hatte gehofft, dass ich das 'Response' Objekt einfach wiederverwenden könnte. Bevor OkHttp verwendet wurde, habe ich ein angepasstes ApiResult-Objekt zurückgegeben, wo ich gerade alle relevanten Informationen gespeichert habe, aber es ist nur ein Duplikat IMO. – degill

+0

vielleicht sollten Sie diese [Problem] (https://github.com/square/okhttp/issues/1240) auf Github überprüfen. – penkzhou

+0

Ich verstehe deinen Standpunkt. Ich denke, sie wollten es nur so niedrig wie möglich halten, ohne das Ergebnis zwischenzuspeichern, das nie wieder aufgerufen wird. –

20

Zur Erläuterung des Problems sehen Greg Ennis' answer.

Wenn Sie jedoch nicht einfach das Ergebnis in einer Variable übergeben kann, muss aber noch zweimal den Antworttext zuzugreifen haben Sie eine weitere Option:

Clone der Puffer, bevor es zu lesen. Dadurch wird der ursprüngliche Puffer weder geleert noch geschlossen. Sehen Sie diesen Schnipsel:

ResponseBody responseBody = response.body(); 
BufferedSource source = responseBody.source(); 
source.request(Long.MAX_VALUE); // request the entire body. 
Buffer buffer = source.buffer(); 
// clone buffer before reading from it 
String responseBodyString = buffer.clone().readString(Charset.forName("UTF-8")) 
Log.d("TAG", responseBodyString); 

Dieser Ansatz in HttpLoggingInterceptor in Projekt okhttp von Platz selbst verwendet wird.

+0

vielen Dank Mann. Wirklich benötigt auf diese Weise andere weise ich hätte es in 20-30 Orten ändern müssen :) –

1

BTW Zusätzlich zu Greg Ennis 'Antwort kann ich sagen, was mir einst passierte, als ich response.body(). String() im Watch-Fenster vergaß. Unter dem Debugger lies der Body also in die Uhr und der Netzwerkstream wurde danach geschlossen.

0

Erweitern Sie ein wenig auf die Antworten von user2011622 und Greg Ennis, ich erstellte eine Methode, die Ihnen hilft, einen vollständigen Klon des Körpers zu erstellen, so dass Sie jede Kopie des Körpers getrennt konsumieren können. Ich benutze diese Methode selbst mit Retrofit2

+0

Rufen Sie einfach die Methode mit der Antwort, erhalten Sie eine weitere Kopie des Antwortkörpers zurück, aber das Original wird verfügbar bleiben (offen) –

+0

in den Quellen suchen und implementieren das gleiche, was ich für den vorherigen habe (neue Herkunft aus geklonter Quelle), ich bin nicht vertraut damit –

Verwandte Themen