Estoy haciendo una solicitud de obtención de HTTP a un sitio web para una aplicación de Android que estoy haciendo.
Estoy usando un DefaultHttpClient y estoy usando HttpGet para emitir la solicitud. Obtengo la respuesta de la entidad y de esto obtengo un objeto InputStream para obtener el html de la página.
Luego paso por la respuesta haciendo lo siguiente:
BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
String x = "";
x = r.readLine();
String total = "";
while(x!= null){
total += x;
x = r.readLine();
}
Sin embargo, esto es terriblemente lento.
¿Es esto ineficiente? No estoy cargando una página web grande: www.cokezone.co.uk, por lo que el tamaño del archivo no es grande. ¿Hay una mejor manera de hacer esto?
Gracias
Andy
Respuestas:
El problema en su código es que está creando muchos
String
objetos pesados , copiando su contenido y realizando operaciones en ellos. En su lugar, debe usarStringBuilder
para evitar crear nuevosString
objetos en cada apéndice y para evitar copiar las matrices de caracteres. La implementación para su caso sería algo como esto:Ahora puede usarlo
total
sin convertirloString
, pero si necesita el resultado como aString
, simplemente agregue:Resultado de cadena = total.toString ();
Trataré de explicarlo mejor ...
a += b
(oa = a + b
), dondea
yb
son cadenas, copia el contenido de ambosa
yb
en un nuevo objeto (tenga en cuenta que también está copiandoa
, que contiene el acumuladoString
), y está haciendo esas copias en cada iteración.a.append(b)
, dondea
es aStringBuilder
, agregab
contenido directamentea
, de modo que no copie la cadena acumulada en cada iteración.fuente
StringBuilder total = new StringBuilder(inputStream.available());
readline
bucle es ridículo. Ese patrón debería haber muerto con verde guisante en los años 70.¿Has probado el método incorporado para convertir una secuencia en una cadena? Es parte de la biblioteca Apache Commons (org.apache.commons.io.IOUtils).
Entonces su código sería esta línea:
La documentación para ello se puede encontrar aquí: http://commons.apache.org/io/api-1.4/org/apache/commons/io/IOUtils.html#toString%28java.io.InputStream%29
La biblioteca Apache Commons IO se puede descargar desde aquí: http://commons.apache.org/io/download_io.cgi
fuente
Otra posibilidad con guayaba:
dependencia:
compile 'com.google.guava:guava:11.0.2'
fuente
Creo que esto es lo suficientemente eficiente ... Para obtener una cadena de un InputStream, llamaría al siguiente método:
Siempre uso UTF-8. Podría, por supuesto, establecer charset como argumento, además de InputStream.
fuente
¿Qué hay de esto? Parece dar un mejor rendimiento.
Editar: en realidad, este tipo abarca tanto steelbytes como Maurice Perry
fuente
Posiblemente algo más rápido que la respuesta de Jaime Soriano, y sin los problemas de codificación de varios bytes de la respuesta de Adrian, sugiero:
fuente
Tal vez, en lugar de leer 'una línea a la vez' y unir las cadenas, intente 'leer todas las disponibles' para evitar el escaneo en busca de fin de línea y también evitar uniones de cadenas.
es decir,
InputStream.available()
yInputStream.read(byte[] b), int offset, int length)
fuente
Leer una línea de texto a la vez y agregar dicha línea a una cadena individualmente lleva mucho tiempo, tanto en la extracción de cada línea como en la sobrecarga de tantas invocaciones de métodos.
Pude obtener un mejor rendimiento al asignar una matriz de bytes de tamaño decente para contener los datos de la secuencia, y que se reemplaza iterativamente por una matriz más grande cuando es necesario, y al tratar de leer tanto como la matriz podría contener.
Por alguna razón, Android repetidamente no pudo descargar el archivo completo cuando el código usó el InputStream devuelto por HTTPUrlConnection, por lo que tuve que recurrir al uso de un BufferedReader y un mecanismo de tiempo de espera manual para asegurarme de obtener el archivo completo o cancelar la transferencia.
EDITAR: Resulta que si no necesita tener el contenido codificado de nuevo (es decir, si desea el contenido TAL CUAL ), no debe usar ninguna de las subclases de Reader. Simplemente use la subclase Stream adecuada.
Reemplace el comienzo del método anterior con las líneas correspondientes de lo siguiente para acelerarlo de 2 a 3 veces más .
fuente
Si el archivo es largo, puede optimizar su código agregando un StringBuilder en lugar de usar una concatenación de String para cada línea.
fuente
fuente
Para convertir InputStream a String, utilizamos el método BufferedReader.readLine () . Repetimos hasta que BufferedReader devuelva nulo, lo que significa que no hay más datos para leer. Cada línea se agregará a un StringBuilder y se devolverá como String.
Y finalmente, desde cualquier clase donde quieras convertir llama a la función
completar
fuente
Estoy acostumbrado a leer datos completos:
fuente