10

アプリケーションを初めて実行するときに、Web サービスへの SOAP 呼び出しを介して大量のデータをアプリケーションにダウンロードする必要があるアプリケーションがあります。応答は、XML を変換してデータを db ファイルに保存する関数に送信されます。

データのサイズは 16 MB を超えており、毎回 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

Just an update, I found that the "call" method in AndroidHttpTransport was running out of memory at this line -

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

the call to toByteArray takes a lot of memory, so to overcome this, instead of converting the response to a byte array, i now directly write it to an XML file, and this is saved at a location of my choice. Here -

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

The device no longer runs out of memory, and i have a custom parse method that takes this XML and writes it to the DB.

于 2011-02-13T10:24:37.850 に答える
5

この問題の解決に役立つ 2 つの戦略:

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

ここで、「file」は new File("/sdcard/","myFile.xml") のような単純なファイル オブジェクトです。

于 2012-10-04T17:18:27.617 に答える