Подтвердить что ты не робот

Как решить проблему синтаксического анализа XML на Android

Мне нужно прочитать XML файл с примерно 4000 строк на Android. Сначала я попробовал SimpleXML library, потому что это было проще всего, и мне потребовалось около 2 минут на моем HTC Desire. Поэтому я подумал, что SimpleXML настолько медленный из-за отражения и всей магии, что использует эта библиотека. Я переписал свой парсер и использовал встроенный метод разбора DOM с особым вниманием к производительности. Это немного помогло, но все равно потребовалось около 60 секунд, что по-прежнему совершенно неприемлемо. После небольшого исследования я нашел эту статью на developer.com. Есть несколько графиков, которые показывают, что два других доступных метода - парсер SAX и Android Pull-Parser - одинаково медленны. И в конце статьи вы найдете следующее утверждение:

Первый сюрприз, который я имел, заключался в том, насколько медленны все три метода. пользователей не хотят долго ждать результатов на мобильных телефонах, поэтому синтаксический анализ более чем несколько десятков записей могут указывать на другой метод.

Что может быть "другим методом"? Что делать, если у вас больше, чем "несколько десятков записей"?

4b9b3361

Ответ 1

Оригинальный ответ, в 2012 году

(обратите внимание: убедитесь, что вы читаете обновление 2016 ниже!)

Я просто немного перфорировал тестирование парсеров на Android (и других платформах). Обработанный XML файл составляет всего 500 строк (его твиттер Atom Atom), но анализ Pull и DOM может перехватить примерно 5 таких документов в секунду на Samsung Galaxy S2 или Motorola Xoom2. SimpleXML (розовый на диаграмме), используемый OP-узлами для самых медленных сеансов DOM.

SAX Parsing на порядок выше на обоих Android-устройствах, управляя одноточечной записью 40 документов/сек и 65 +/сек многопоточными.

Android 2.3.4:

performance comparison of xml parsing methods on Android

code доступен в github, а обсуждение здесь.

Обновление 18 марта 2016 года

ОК, так что прошло почти 4 года, и мир двинулся дальше. Я, наконец, начал повторять тесты:

  • Samsung Galaxy S3 работает под управлением Android 4.1.2.
  • Nexus7 (2012) под управлением Android 4.4.4
  • Nexus5 работает под управлением Android 6.0.1

Где-то между Android 4.4.4 и Android 6.0.1 ситуация резко изменилась, и у нас появился новый победитель: Pull Parsing FTW более чем в два раза превышает пропускную способность SAX. К сожалению, я точно не знаю, когда это изменение прибыло, поскольку у меня нет устройств с Android > 4.4.4 и < 6.0.1.

Android 4.1.2:

performance comparison of xml parsing methods on Android 4.1.2

Android 4.4.4:

performance comparison of xml parsing methods on Android 4.4.4

Android 6.0.1:

performance comparison of xml parsing methods on Android 6.0.1

Ответ 2

Я думаю, что лучший способ работать с XML на Android - это библиотека VDT-XML

Мой XML файл содержит более 60 000 строк, а VDT-XML обрабатывает его следующим образом:

Nexus 5: 2055 миллисекунд

Galaxy Note 4: 2498 milisec

Более подробные отчеты можно найти по ссылке: VTD-XML Benchmark

Краткий пример файла XML

 <database name="products">
        <table name="category">
            <column name="catId">20</column>
            <column name="catName">Fruit</column>
        </table>
        <table name="category">
            <column name="catId">31</column>
            <column name="catName">Vegetables</column>
        </table>
        <table name="category">
            <column name="catId">45</column>
            <column name="catName">Rice</column>
        </table>
        <table name="category">
            <column name="catId">50</column>
            <column name="catName">Potatoes</column>
        </table>
</database>

Конфигурация файла "build.gradle"

dependencies {
    compile files('libs/vtd-xml.jar')
}

Пример исходного кода:

import com.ximpleware.AutoPilot;
import com.ximpleware.VTDGen;
import com.ximpleware.VTDNav;


String fileName = "products.xml";

VTDGen vg = new VTDGen();

if (vg.parseFile(fileName, true)) {

     VTDNav vn = vg.getNav();
     AutoPilot table = new AutoPilot(vn);
     table.selectXPath("database/table");

     while (table.iterate()) {
        String tableName = vn.toString(vn.getAttrVal("name"));

        if (tableName.equals("category")) {
            AutoPilot column = new AutoPilot(vn);
            column.selectElement("column");

            while (column.iterate()) {
                 String text = vn.toNormalizedString(vn.getText());
                 String name = vn.toString(vn.getAttrVal("name"));

                 if (name.equals("catId")) {
                    Log.d("Category ID = " + text);
                 } else if (name.equals("catName")) {
                    Log.d("Category Name = " + text);
                 } 

            }
        }
     }
}

Результат

Category ID = 20
Category Name = Fruit

Category ID = 31
Category Name = Vegetables

Category ID = 45
Category Name = Rice

Category ID = 50
Category Name = Potatoes

это работает для меня и надеюсь, что это поможет вам.

Ответ 3

Используя синтаксический анализатор SAX, я могу проанализировать XML файл размером 15 000 строк примерно за 10 секунд на моем HTC Desire. Я подозреваю, что есть другая проблема.

Вы заполняете базу данных из XML? Если да, помните ли вы, что вы завершаете всю операцию анализа в транзакции БД? Только это может ускорить процесс на порядок.

Ответ 4

Если вы разбираете даты в своем XML, что может значительно замедлить ваш синтаксический анализ. С более поздними версиями Android это становится менее проблематичным (поскольку они оптимизировали загрузку информации о часовом поясе)

Если у вас есть Даты, которые обрабатываются, и они вам не нужны, вы можете использовать SAX-парсер и игнорировать любой элемент Date.

Или, если вы можете изменить схему XML, подумайте о том, чтобы хранить даты как целые числа, а не форматированные строки.

Вы упомянули, что вы делаете сравнения строк, это может быть довольно дорого. Возможно, подумайте об использовании HashMap для сравниваемых строк, это может дать заметные преимущества производительности.

Ответ 5

Очень сложно рассказать вам, почему ваш код медленный, не видя ваш код, и очень сложно поверить в ваше утверждение о том, что медленность связана с парсером XML, когда вы не представили детали каких-либо измерений, чтобы доказать это.

Ответ 6

мы используем pull-parser очень эффективно для 1MB XML файлов - и они читаются примерно через 10-20 секунд по моему желанию. Поэтому, если ваш код в порядке, скорость будет такой же. Очевидно, что DOM очень медленный в ограниченной среде памяти, но pull или SAX действительно не

Ответ 7

Если ваш синтаксический разбор из Socket его ввода-вывода занимает время, а не синтаксический анализ. Попробуйте сначала использовать данные, затем разобрать один раз и измерить производительность. Если файл слишком большой, то рассмотрите BufferedInputStream с очень большим буфером, это должно повысить производительность для вас.

Я очень серьезно сомневаюсь Простой XML займет 2 минуты, чтобы загрузить 4000 строк, я понимаю, что телефон будет намного медленнее чем рабочая станция, однако я могу загрузить 200 000 строк XML в 600 мс на моей рабочей станции.

Ответ 8

Вместо того, чтобы сделать это синхронным процессом, сделайте его асинхронным. У вас может быть кнопка, которая запускает IntentService, который будет обрабатывать данные для вас, и обновит результаты и покажет уведомление, когда это будет сделано. Таким образом, вы не останавливаете поток пользовательского интерфейса.