2011-02-09 23 views
10

Tengo una aplicación donde necesito descargar una gran cantidad de datos a través de una llamada SOAP a un servicio web en la aplicación cuando se ejecuta por primera vez. La respuesta se envía a una función que convierte el XML y almacena los datos en un archivo db.Respuesta SOAP muy grande - Android - error de memoria

Los datos tienen más de 16 MB de tamaño y tengo java.lang.OutOfMemoryError cada vez.

La modificación del servicio web para proporcionar pequeñas cantidades de datos no es una opción.

¿Hay alguna manera de poder descargar los datos de gran tamaño? Algo como un InputStream tal vez?

Este es mi código

public Protocol[] getProtocols() { 

    String METHOD_NAME = "GetProtocols"; 
    String SOAP_ACTION = "urn:protocolpedia#GetProtocols"; 
    Log.d("service", "getProtocols"); 
    SoapObject response = invokeMethod(METHOD_NAME, SOAP_ACTION); 
    return retrieveProtocolsFromSoap(response); 
} 

private SoapObject invokeMethod(String methodName, String soapAction) { 
    Log.d(TAG, "invokeMethod"); 
    SoapObject request = GetSoapObject(methodName); 
    SoapSerializationEnvelope envelope = getEnvelope(request); 
    return makeCall(envelope, methodName, soapAction); 

} 

Puede alguien sugerir qué se debe hacer en este caso?

Gracias y saludos Mukul

+0

I Creo que vtd-xml puede ayudar a reducir el uso de memoria. –

+0

@ vtd-xml-author - ¿también funciona para android? –

Respuesta

5

Dos estrategias para ayudar a solucionar este problema:

  1. Guarde su secuencia XML de SOAP directamente en el disco como de descargarlo. No lo guarde en la memoria.
  2. Analízalo con un analizador de estilo SAX, donde no se carga todo el DOM en la memoria, sino que se analiza en trozos.

Dependiendo del tipo de XML que esté manejando, el uso de analizadores SAX suele ser más difícil en el código; tendrá que hacer un seguimiento de muchas cosas usted mismo, y no podrá "saltar" de una sección a otra de su árbol DOM. Pero el consumo de memoria será mucho menor.

Tenga en cuenta, sin embargo, que muchas bibliotecas de comunicación de red de "alto nivel" generalmente cargan todo el XML DOM en la memoria, lo que podría ser el caso aquí. Probablemente tendrá que crear y administrar la conexión HTTP usted mismo, y luego analizar manualmente el resultado.

+1

Hola Adrian, Gracias por la respuesta, lo he intentado y funciona bien, en este caso, el archivo XML en sí tiene unos 8 MB de tamaño. Consulte mi respuesta a continuación, he pegado el código para hacerlo también, para referencia futura –

6

Apenas una actualización, he encontrado que el método de "llamada" en AndroidHttpTransport estaba quedando sin memoria en esta línea -

  if (debug) { 
        ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
        byte[] buf = new byte[256]; 
        while (true) { 
         int rd = is.read(buf, 0, 256); 
         if (rd == -1) 
          break; 
         bos.write(buf, 0, rd); 
        } 
        bos.flush(); 
        buf = bos.toByteArray(); //Goes out of memory here 
        responseDump = new String(buf); 
        is.close(); 
        is = new ByteArrayInputStream(buf); 

la llamada a toByteArray toma mucho de memoria, así que para superar esto, en lugar de convertir la respuesta a una matriz de bytes, ahora directamente lo escribo en un archivo XML, y esto se guarda en una ubicación de mi elección. Aquí -

if (debug) { 
    FileOutputStream bos = new FileOutputStream("/data/data/com.mypackage.myapp/response.xml"); 
    byte[] buf = new byte[1048576]; 
    int current = 0; int i=0; int newCurrent = 0; 
    while ((current = inputStream.read(buf)) != -1) { 
     newCurrent = newCurrent + current; 
    Log.d("current", "Current = " + current + " total = "+newCurrent+" i = "+i++); 
        bos.write(buf, 0, current); 
       } 
       bos.flush(); 
} 

El dispositivo ya no se queda sin memoria, y tengo un método de análisis personalizado que lleva este XML y lo escribe en la base de datos.

+3

¿Cómo usaste esto con 'SoapObject' en' SoapSerializationEnvelope'? ¿Puedes mostrar todo tu ejemplo llamando al servicio web utilizando ksoap2 y escribiendo los resultados en un archivo en lugar de serializarlos en un 'SoapObject'? –

+0

Necesito su ejemplo también. Pls publíquelo – kinghomer

+0

Gracias Mukul por su respuesta. Sin embargo, no está claro cómo obtuvo la respuesta. Puede proporcionar su método completo para obtener la respuesta y guardarla en un archivo. ¿Qué hay de llamar al servicio web makeCall (envelope, methodName, soapAction);? – joy

1

¡Reparado!

He descargado/copiado HttpTransportSE clase java de aquí (después de copiado, pueden ocurrir algunos errores de código, pero todos ellos son rápida corregible) y se añadió a mi paquete:

https://github.com/mosabua/ksoap2-android/blob/master/ksoap2-j2se/src/main/java/org/ksoap2/transport/HttpTransportSE.java 

eliminado de mi clase de conexión de esta fila :

import org.ksoap2.transport.HttpsTransportSE; 

y sustituido este código en mi nuevo HttpTransportSE.archivo Java:

if (debug) { 
        ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
        byte[] buf = new byte[256]; 
        while (true) { 
         int rd = is.read(buf, 0, 256); 
         if (rd == -1) 
          break; 
         bos.write(buf, 0, rd); 
        } 
        bos.flush(); 
        buf = bos.toByteArray(); //Goes out of memory here 
        responseDump = new String(buf); 
        is.close(); 
        is = new ByteArrayInputStream(buf); 
    } 

con este

if (debug) { 
    FileOutputStream bos = new FileOutputStream(file); 

      byte[] buf = new byte[256]; 

      while (true) { 
       int rd = is.read(buf, 0, 256); 
       if (rd == -1) { 
        break; 
       } 
       bos.write(buf, 0, rd); 
      } 
      bos.flush(); 
} 

donde "archivo" es un objeto simple de archivos como nuevo archivo ("/ sdcard /", "myfile.xml"), por ejemplo

+1

Lo he implementado en ksoap2-android 3.0.0-RC.5-SNAPSHOT. ¿Podrías probar si funciona para ti? –

+0

Ok, intentaré publicar el resultado lo antes posible – kinghomer

+0

@kinghomer He utilizado el mismo código y nunca he recibido la excepción OutOfMemory, pero ahora estoy obteniendo org.xmlpull.v1.XmlPullParserException: tipo inesperado (posición: END_DOCUMENT null @ 1: 1 en [email protected]) Tu ayuda será como el diamante para mí ... – Araju

Cuestiones relacionadas