Wysyłam żądanie HTTP get do witryny internetowej dla tworzonej przeze mnie aplikacji na Androida.
Używam DefaultHttpClient i używam HttpGet do wystawiania żądania. Otrzymuję odpowiedź jednostki iz tego otrzymuję obiekt InputStream w celu pobrania kodu HTML strony.
Następnie przechodzę przez odpowiedź w następujący sposób:
BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
String x = "";
x = r.readLine();
String total = "";
while(x!= null){
total += x;
x = r.readLine();
}
Jednak jest to horrendalnie powolne.
Czy to jest nieefektywne? Nie ładuję dużej strony internetowej - www.cokezone.co.uk, więc rozmiar pliku nie jest duży. Czy jest lepszy sposób na zrobienie tego?
Dzięki
Andy
Odpowiedzi:
Problem w twoim kodzie polega na tym, że tworzy on wiele ciężkich
String
obiektów, kopiuje ich zawartość i wykonuje na nich operacje. Zamiast tego należy używać,StringBuilder
aby uniknąć tworzenia nowychString
obiektów przy każdym dołączaniu i aby uniknąć kopiowania tablic char. Implementacja dla twojego przypadku wyglądałaby mniej więcej tak:Możesz teraz używać
total
bez konwertowania go naString
, ale jeśli potrzebujesz wyniku jako aString
, po prostu dodaj:Wynik w postaci ciągu = total.toString ();
Postaram się to lepiej wyjaśnić ...
a += b
(luba = a + b
), gdziea
ib
są ciągami, kopiuje zawartość obua
ib
do nowego obiektu (zwróć uwagę, że kopiujesz równieża
, który zawiera nagromadzoneString
) i robisz te kopie w każdej iteracji.a.append(b)
, gdziea
jest aStringBuilder
, bezpośrednio dołączab
zawartość doa
, więc nie kopiujesz skumulowanego ciągu w każdej iteracji.źródło
StringBuilder total = new StringBuilder(inputStream.available());
readline
pętli każdego fragmentu kodu w sieci i aplikacji na świecie jest absurdalne. Ten wzór powinien był umrzeć wraz z zielenią grochu w latach 70.Czy wypróbowałeś wbudowaną metodę konwersji strumienia na ciąg? Jest częścią biblioteki Apache Commons (org.apache.commons.io.IOUtils).
Wtedy twój kod byłby tym jednym wierszem:
Dokumentację do tego można znaleźć tutaj: http://commons.apache.org/io/api-1.4/org/apache/commons/io/IOUtils.html#toString%28java.io.InputStream%29
Bibliotekę Apache Commons IO można pobrać tutaj: http://commons.apache.org/io/download_io.cgi
źródło
Inna możliwość z guawą:
zależność:
compile 'com.google.guava:guava:11.0.2'
źródło
Uważam, że jest to wystarczająco wydajne ... Aby uzyskać String z InputStream, wywołałbym następującą metodę:
Zawsze używam UTF-8. Możesz oczywiście ustawić charset jako argument, oprócz InputStream.
źródło
A co z tym. Wydaje się, że zapewnia lepszą wydajność.
Edycja: Właściwie ten rodzaj obejmuje zarówno steelbytes, jak i Maurice Perry's
źródło
Prawdopodobnie nieco szybciej niż odpowiedź Jaime Soriano i bez problemów z wielobajtowym kodowaniem odpowiedzi Adriana, proponuję:
źródło
Może zamiast tego przeczytaj „jeden wiersz na raz” i połącz łańcuchy, spróbuj „przeczytaj wszystkie dostępne”, aby uniknąć przeszukiwania końca wiersza, a także łączenia łańcuchów.
ie,
InputStream.available()
iInputStream.read(byte[] b), int offset, int length)
źródło
Czytanie jednego wiersza tekstu na raz i dołączanie tego wiersza do łańcucha osobno jest czasochłonne zarówno w przypadku wyodrębniania każdego wiersza, jak i narzutu związanego z tak wieloma wywołaniami metod.
Udało mi się uzyskać lepszą wydajność, przydzielając tablicę bajtów przyzwoitej wielkości do przechowywania danych strumienia, która w razie potrzeby jest iteracyjnie zastępowana większą tablicą i próbując odczytać tyle, ile mogła pomieścić tablica.
Z jakiegoś powodu system Android wielokrotnie nie mógł pobrać całego pliku, gdy kod wykorzystywał InputStream zwracany przez HTTPUrlConnection, więc musiałem skorzystać zarówno z BufferedReader, jak i ręcznie zwijanego mechanizmu limitu czasu, aby upewnić się, że otrzymam cały plik lub anuluję transfer.
EDYCJA: Okazuje się, że jeśli nie musisz ponownie kodować treści (tj. Chcesz, aby treść była taka, jaka jest ), nie powinieneś używać żadnej z podklas Reader. Po prostu użyj odpowiedniej podklasy Stream.
Zastąp początek poprzedniej metody odpowiednimi wierszami poniższego, aby przyspieszyć ją dodatkowo 2 do 3 razy .
źródło
Jeśli plik jest długi, możesz zoptymalizować kod, dołączając go do StringBuilder, zamiast używać konkatenacji String dla każdego wiersza.
źródło
źródło
Aby przekonwertować InputStream na String, używamy metody BufferedReader.readLine () . Iterujemy, aż BufferedReader zwróci wartość null, co oznacza, że nie ma więcej danych do odczytania. Każda linia zostanie dołączona do StringBuilder i zwrócona jako String.
I na koniec z dowolnej klasy, w której chcesz przekonwertować, wywołaj funkcję
kompletny
źródło
Czytam pełne dane:
źródło