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

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

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

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

Solutions Collecting From Web of "Как решить проблему производительности синтаксического анализа XML на Android"

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

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

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

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

Android 2.3.4:

Сравнение производительности xml-синтаксического анализа на Android

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

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

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

  1. Samsung Galaxy S3 работает под управлением Android 4.1.2
  2. Nexus7 (2012) под управлением Android 4.4.4
  3. 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:

Сравнение производительности xml-синтаксического анализа на Android 4.1.2

Android 4.4.4:

Сравнение производительности методов XML-анализа на Android 4.4.4

Android 6.0.1:

Сравнение производительности xml-синтаксического анализа на Android 6.0.1

Я думаю, что лучшим способом работы с 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 

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

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

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

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

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

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

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

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

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

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

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

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