【问题标题】:Very large SOAP response - Android- out of memory error非常大的 SOAP 响应 - Android - 内存不足错误
【发布时间】:2011-02-09 05:18:18
【问题描述】:

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

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

修改网络服务以提供更少量的数据不是一种选择。

有没有办法可以下载大数据?可能是 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);

}

谁能建议在这种情况下应该怎么做?

感谢和问候 穆库尔

【问题讨论】:

  • 我认为 vtd-xml 无疑可以帮助降低内存使用率。

标签: android soap android-ksoap2


【解决方案1】:

刚刚更新,我发现AndroidHttpTransport中的“调用”方法在这一行内存不足 -

           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 并将其写入数据库。

【讨论】:

  • 您是如何将其与SoapSerializationEnvelope 中的SoapObject 一起使用的?您能否展示您的整个示例,使用 ksoap2 调用 Web 服务,并将结果写入文件而不是将它们序列化为 SoapObject
  • 感谢 Mukul 的回答。但不清楚您是如何获得响应的。您能否提供获取响应并将其保存到文件的整个方法。调用 web 服务 makeCall(信封、方法名、soapAction);?
  • @Octavian Damiean 我使用了相同的代码,然后从未出现 OutOfMemory 异常,但我现在得到 org.xmlpull.v1.XmlPullParserException: 意外类型(位置:END_DOCUMENT null@1:1 in java.lang. io.InputStreamReader@2fe6cc09) 你的帮助对我来说就像钻石..
【解决方案2】:

两种策略帮你解决这个问题:

  1. 下载时将 SOAP XML 流直接保存到磁盘。不要将其存储在内存中。
  2. 使用 SAX 样式的解析器对其进行解析,您不会将整个 DOM 加载到内存中,而是将其解析为块。

根据您处理的 XML 类型,在代码中使用 SAX 解析器通常更难;您将不得不自己跟踪许多事情,并且您将无法从 DOM 树的一个部分“跳转”到另一个部分。但是内存消耗会低很多。

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

【讨论】:

  • 嗨,Adrian,感谢您的回复,我已经尝试过了,效果很好,在这种情况下,XML 文件本身的大小约为 8 MB。请在下面查看我的答案,我也粘贴了代码,以供将来参考
【解决方案3】:

已修复!

我从这里下载/复制了 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”是一个简单的文件对象,例如 new File("/sdcard/","myFile.xml")

【讨论】:

  • 我已经在 ksoap2-android 3.0.0-RC.5-SNAPSHOT 中实现了这个。你可以试试它是否适合你?
  • 好的,我会尽快发布结果
  • @kinghomer 我使用了相同的代码,然后从未得到 OutOfMemory 异常,但我现在得到 org.xmlpull.v1.XmlPullParserException: 意外类型(java.io 中的位置:END_DOCUMENT null@1:1 .InputStreamReader@2fe6cc09) 你的帮助对我来说就像钻石..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-01
  • 1970-01-01
  • 2013-01-17
  • 2012-03-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多