10

我有一个应用程序,我需要在首次运行时通过对 Web 服务的 SOAP 调用将大量数据下载到应用程序中。然后将响应发送到转换 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);

}

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

感谢和问候穆库尔

4

3 回答 3

6

只是一个更新,我发现 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 并将其写入数据库。

于 2011-02-13T10:24:37.850 回答
5

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

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

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

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

于 2011-02-13T10:29:59.077 回答
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();
}

where "file" is a simple file object like new File("/sdcard/","myFile.xml") for example

于 2012-10-04T17:18:27.617 回答