Ich mache eine HTTP-Get-Anfrage an eine Website für eine Android-Anwendung, die ich mache.
Ich verwende einen DefaultHttpClient und HttpGet, um die Anforderung auszugeben. Ich erhalte die Entitätsantwort und erhalte daraus ein InputStream-Objekt zum Abrufen des HTML-Codes der Seite.
Ich gehe dann die Antwort wie folgt durch:
BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
String x = "";
x = r.readLine();
String total = "";
while(x!= null){
total += x;
x = r.readLine();
}
Dies ist jedoch schrecklich langsam.
Ist das ineffizient? Ich lade keine große Webseite - www.cokezone.co.uk, daher ist die Dateigröße nicht groß. Gibt es einen besseren Weg, dies zu tun?
Vielen Dank
Andy
Antworten:
Das Problem in Ihrem Code besteht darin, dass viele schwere
String
Objekte erstellt, deren Inhalt kopiert und Operationen an ihnen ausgeführt werden. Verwenden Sie stattdessen, umStringBuilder
zu vermeiden, dassString
an jedem Anhang neue Objekte erstellt werden, und um zu vermeiden, dass die char-Arrays kopiert werden. Die Implementierung für Ihren Fall wäre ungefähr so:Sie können es jetzt verwenden,
total
ohne es zu konvertieren.String
Wenn Sie das Ergebnis jedoch als benötigenString
, fügen Sie einfach Folgendes hinzu:String result = total.toString ();
Ich werde versuchen, es besser zu erklären ...
a += b
(odera = a + b
), wobeia
undb
Zeichenfolgen sind, kopiert den Inhalt von beidena
undb
in ein neues Objekt (beachten Sie, dass Sie auch kopierena
, das die akkumulierten enthältString
), und Sie kopieren diese bei jeder Iteration.a.append(b)
, woa
ist einStringBuilder
, hängt denb
Inhalt direkt ana
, sodass Sie die akkumulierte Zeichenfolge nicht bei jeder Iteration kopieren.quelle
StringBuilder total = new StringBuilder(inputStream.available());
readline
ist lächerlich, wenn jedes Code-Snippet im Web und jede App auf dem Planeten eine Schleife erneut implementiert . Dieses Muster sollte in den 70er Jahren mit Erbsengrün gestorben sein.Haben Sie die integrierte Methode zum Konvertieren eines Streams in einen String ausprobiert? Es ist Teil der Apache Commons-Bibliothek (org.apache.commons.io.IOUtils).
Dann wäre Ihr Code diese eine Zeile:
Die Dokumentation dazu finden Sie hier: http://commons.apache.org/io/api-1.4/org/apache/commons/io/IOUtils.html#toString%28java.io.InputStream%29
Die Apache Commons IO-Bibliothek kann hier heruntergeladen werden: http://commons.apache.org/io/download_io.cgi
quelle
Eine andere Möglichkeit mit Guave:
Abhängigkeit:
compile 'com.google.guava:guava:11.0.2'
quelle
Ich glaube, das ist effizient genug ... Um einen String aus einem InputStream zu erhalten, würde ich die folgende Methode aufrufen:
Ich benutze immer UTF-8. Neben InputStream können Sie natürlich auch den Zeichensatz als Argument festlegen.
quelle
Was ist damit? Scheint eine bessere Leistung zu geben.
Bearbeiten: Eigentlich umfasst diese Art sowohl Steelbytes als auch Maurice Perrys
quelle
Möglicherweise etwas schneller als Jaime Sorianos Antwort, und ohne die Multi-Byte-Codierungsprobleme von Adrians Antwort schlage ich vor:
quelle
Vielleicht lesen Sie lieber "eine Zeile nach der anderen" und verbinden Sie die Zeichenfolgen. Versuchen Sie "Alle verfügbaren lesen", um das Scannen nach Zeilenende und das Verknüpfen von Zeichenfolgen zu vermeiden.
dh
InputStream.available()
undInputStream.read(byte[] b), int offset, int length)
quelle
Das Lesen von jeweils einer Textzeile und das Anhängen dieser Zeile an eine Zeichenfolge ist sowohl beim Extrahieren jeder Zeile als auch beim Overhead so vieler Methodenaufrufe zeitaufwändig.
Ich konnte eine bessere Leistung erzielen, indem ich ein Byte-Array mit angemessener Größe für die Stream-Daten zuordnete, das bei Bedarf iterativ durch ein größeres Array ersetzt wird, und versuchte, so viel zu lesen, wie das Array aufnehmen konnte.
Aus irgendeinem Grund konnte Android wiederholt nicht die gesamte Datei herunterladen, wenn der Code den von HTTPUrlConnection zurückgegebenen InputStream verwendete. Daher musste ich sowohl einen BufferedReader als auch einen handgerollten Timeout-Mechanismus verwenden, um sicherzustellen, dass ich entweder die gesamte Datei erhalten oder abbrechen würde die Übertragung.
EDIT: Es stellt sich heraus , dass , wenn Sie nicht den Inhalt neucodierte haben müssen (dh der Inhalt wollen AS IS ) Sie sollten keine der Reader - Subklassen verwenden. Verwenden Sie einfach die entsprechende Stream-Unterklasse.
Ersetzen Sie den Anfang der vorhergehenden Methode durch die entsprechenden Zeilen der folgenden, um sie zwei- bis dreimal zu beschleunigen .
quelle
Wenn die Datei lang ist, können Sie Ihren Code optimieren, indem Sie ihn an einen StringBuilder anhängen, anstatt für jede Zeile eine String-Verkettung zu verwenden.
quelle
quelle
Um den InputStream in String zu konvertieren, verwenden wir die BufferedReader.readLine () -Methode. Wir iterieren, bis der BufferedReader null zurückgibt , was bedeutet, dass keine Daten mehr zu lesen sind. Jede Zeile wird an einen StringBuilder angehängt und als String zurückgegeben.
Und schließlich rufen Sie aus jeder Klasse, in die Sie konvertieren möchten, die Funktion auf
Komplett
quelle
Ich bin es gewohnt, vollständige Daten zu lesen:
quelle