Как решить проблему производительности XML-анализа на Android - PullRequest
16 голосов
/ 29 августа 2011

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

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

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

Ответы [ 8 ]

34 голосов
/ 14 апреля 2012

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

(примечание: обязательно прочитайте обновление 2016 года ниже!)

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

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

Android 2.3.4:

performance comparison of xml parsing methods on Android

Доступен код в github и обсуждение здесь .

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

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

  1. Samsung Galaxy S3 под управлением Android 4.1.2
  2. A 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. </p>

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

5 голосов
/ 09 апреля 2015

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

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

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

Galaxy Note 4: 2498 милисек

Дополнительные отчеты о тестировании можно найти по ссылке: Тест VTD-XML

Краткий пример 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

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

0 голосов
/ 03 марта 2012

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

0 голосов
/ 29 августа 2011

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

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

0 голосов
/ 29 августа 2011

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

0 голосов
/ 29 августа 2011

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

0 голосов
/ 29 августа 2011

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

Если у вас есть анализируемые даты и они вам не нужны, тогда вы можете использоватьАнализатор SAX и игнорирование любого из элементов Date.

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

0 голосов
/ 29 августа 2011

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

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

...