非常大的SOAP响应 - Android-内存不足错误

时间:2011-02-09 05:18:19

标签: android soap android-ksoap2

我有一个应用程序,我需要在首次运行时通过SOAP调用将大量数据下载到Web服务中。然后将响应发送到一个函数,该函数转换XML并将数据存储在db文件中。

数据大小超过16MB,每次都有java.lang.OutOfMemoryError。

修改Web服务以提供较少量的数据不是一种选择。

有没有办法可以下载大数据?或许类似于InputStream?

这是我的代码

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);

}

有人可以建议在这种情况下应该做些什么吗?

谢谢和问候 穆库尔

3 个答案:

答案 0 :(得分:6)

只是一个更新,我发现AndroidHttpTransport中的“call”方法在这一行的内存不足 -

           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);

对toByteArray的调用占用了大量内存,因此要克服这个问题,而不是将响应转换为字节数组,我现在直接将其写入XML文件,并将其保存在我选择的位置。在这里 -

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();
}

设备不再耗尽内存,我有一个自定义解析方法,它接受此XML并将其写入数据库。

答案 1 :(得分:5)

两种帮助您解决此问题的策略:

  1. 在下载时将SOAP XML流直接保存到磁盘。不要将其存储在内存中。
  2. 使用SAX样式的解析器解析它,您不会在内存中加载整个DOM,而是以块的形式解析它。
  3. 根据您处理的XML类型,使用SAX解析器通常在代码中更难;你必须自己跟踪很多事情,否则你将无法从你的DOM树的一个部分“跳转”。但内存消耗会低一些。

    但请注意,许多“高级”网络通信库通常会将整个XML DOM加载到内存中,这可能就是这种情况。您可能必须自己创建和管理HTTP连接,然后手动解析结果。

答案 2 :(得分:1)

固定!

我从这里下载/复制了HttpTransportSE java类(复制后,可能会发生一些代码错误,但它们都可以快速修复)并添加到我的包中:

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

从我的Connection类中删除了这一行:

import org.ksoap2.transport.HttpsTransportSE;

并在我的新HttpTransportSE.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);
    }

用这个

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();
}

其中“file”是一个简单的文件对象,例如新文件(“/ sdcard /”,“myFile.xml”),例如