2011-02-09 74 views
10

我有一個應用程序,我需要通過SOAP調用將大量數據下載到應用程序中。然後將響應發送到一個函數,該函數轉換XML並將數據存儲在db文件中。非常大的SOAP響應 - 安卓內存不足錯誤

數據大小超過16MB,每次都有java.lang.OutOfMemoryError。

修改webservice以發出較少量的數據不是一種選擇。

有沒有辦法可以下載大數據?或許像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); 

} 

任何人都可以建議我應該在這種情況下怎麼辦?

感謝和問候 穆庫爾

+0

我認爲vtd-xml無疑可以幫助降低內存使用量。 – 2011-03-13 08:06:20

+0

@ vtd-xml-author - 它也適用於android? – 2011-03-14 10:56:07

回答

5

兩種策略來幫助你解決這個問題:

  1. 直接保存您的SOAP XML流盤,你下載。不要將其存儲在內存中。
  2. 使用SAX風格的解析器解析它,其中不會在內存中加載整個DOM,而是將其解析爲塊。

根據您處理的XML的類型,使用SAX解析器通常在代碼中更難;你將不得不自己跟蹤很多事情,並且你將無法從DOM樹的部分「跳轉」。但內存消耗將會降低。

但是請注意,許多「高級」網絡通信庫通常將整個XML DOM加載到內存中,這可能就是這種情況。您可能必須自己創建和管理HTTP連接,然後手動分析結果。

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並將其寫入到數據庫。

+3

你是如何將這個與SoapSerializationEnvelope中的`SoapObject`一起使用的?你可以通過使用kso​​ap2調用Web服務並將結果寫入文件而不是將它們序列化爲`SoapObject`來顯示整個示例嗎? – 2011-10-06 13:42:55

+0

我也需要你的例子。請發佈 – kinghomer 2012-10-03 16:52:05

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

其中 「文件」 是一個簡單的文件對象像新文件( 「/ SD卡/」, 「myfile.xml中」)例如