Очень большой SOAP-ответ - Android - ошибка памяти - PullRequest
10 голосов
/ 09 февраля 2011

У меня есть приложение, в котором мне нужно загрузить большой объем данных через SOAP-вызов в веб-сервис в приложение при его первом запуске.Затем ответ отправляется функции, которая преобразует XML и сохраняет данные в файле базы данных.

Размер данных превышает 16 МБ, и каждый раз у меня возникает ошибка 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);

}

Кто-нибудь может подсказать, что нужно сделать в этом случае?

Спасибо и с уважением Мукул

Ответы [ 3 ]

6 голосов
/ 13 февраля 2011

Просто обновление, я обнаружил, что у метода "call" в 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 и записывает его в БД.

5 голосов
/ 13 февраля 2011

Две стратегии, которые помогут вам решить эту проблему:

  1. Сохраняйте поток SOAP XML непосредственно на диск при загрузке. Не храните его в памяти.
  2. Анализируйте его, используя синтаксический анализатор в стиле SAX, где вы не загружаете весь DOM в память, а анализируете его порциями.

В зависимости от типа XML, с которым вы работаете, использование SAX-парсеров обычно сложнее в коде; вам придется следить за многими вещами самостоятельно, и вы не сможете «перепрыгивать» из раздела в раздел дерева DOM. Но потребление памяти будет намного ниже.

Обратите внимание, однако, что многие «высокоуровневые» сетевые коммуникационные библиотеки обычно загружают весь XML DOM в память, что может иметь место в данном случае. Вам, вероятно, придется самостоятельно создавать и управлять HTTP-соединением, а затем вручную анализировать результат.

1 голос
/ 04 октября 2012

Исправлено!

Я скачал / скопировал Java-класс HttpTransportSE отсюда (после копирования могут возникнуть некоторые ошибки кода, но все они быстро исправимы) и добавил в мой пакет:

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

удалено из моего класса подключений в этой строке:

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"), например

...