Проблема со скоростью Android при десериализации с использованием SimpleXML

Повышенная награда, поскольку единственный ответ не обеспечивает хорошей реализации для Android. Есть ли более быстрая реализация, совместимая с Android? Или SimpleXML — лучшая производительность, которую я получу?

Я новичок в разработке Java и Android, поэтому не знаю правильной процедуры десериализации строки xml в объект. Я нашел метод, который работает в:

public static Object deserializeXMLToObject(String xmlFile,Object objClass)  throws Exception 
{ 
    try
    {
            InputStream stream = new ByteArrayInputStream(xmlFile.getBytes("UTF-8"));

            Serializer serializer = new Persister();
            objClass = serializer.read(objClass, stream);
            return objClass;
    }
    catch (Exception e) 
    {
        return e;
    }
}

Где xmlFile — это (неверно названная) строка xml, а objClass — это пустой класс класса, который я хочу десериализовать. Обычно это список других объектов.

Пример класса:

@Root(name="DepartmentList")
public class DepartmentList {
    @ElementList(entry="Department", inline=true)
    public List<Department> DepartmentList =new ArrayList<Department>();
    public boolean FinishedPopulating = false;
}

Класс отдела:

public class Department {

    @Element(name="DeptID")
    private String _DeptID ="";
    public String DeptID()
    {
        return _DeptID;
    }
    public void DeptID(String Value)
    {
        _DeptID = Value;
    }

    @Element(name="DeptDescription")
    private String _DeptDescription ="";
    public String DeptDescription()
    {
        return _DeptDescription;
    }
    public void DeptDescription(String Value)
    {
        _DeptDescription = Value;
    }
}

Пример XML:

<DepartmentList>
  <Department>
    <DeptID>525</DeptID>
    <DeptDescription>Dept 1</DeptDescription>
  </Department>
  <Department>
    <DeptID>382</DeptID>
    <DeptDescription>Dept 2</DeptDescription>
  </Department>
</DepartmentList>

Это отлично работает во всем приложении, но я пришел к тому, что ему нужно десериализовать> 300 объектов в списке. Это занимает всего около 5 секунд или около минуты при отладке, но пользователи недовольны такой производительностью и потерей времени, когда отладка нежелательна. Есть ли способ ускорить это? Или есть другой способ, которым я должен это делать? Желательно только изменением метода deserializeXMLToObject.


person anothershrubery    schedule 10.04.2013    source источник
comment
это так просто -- один тип со списком и двумя полями или намного сложнее на самом деле?   -  person hack_on    schedule 02.05.2013
comment
Это один тип, но, вероятно, около 30 полей в 300-400 строках. Я просто упростил это для примера.   -  person anothershrubery    schedule 02.05.2013
comment
Одно из возможных решений — возвращать результаты, не дожидаясь, пока парсер проанализирует все это.   -  person Sherif elKhatib    schedule 07.05.2013
comment
XML работает медленно. Рассмотрите возможность использования другого формата.   -  person stoilkov    schedule 08.05.2013
comment
Может ли кто-нибудь помочь мне с этой ссылкой: stackoverflow.com/questions/22385034/   -  person shaon007    schedule 16.03.2014


Ответы (5)


Я уверен, что кто-то укажет на лучшую библиотеку, но согласно один подробный ответ, все они работают медленно на Android.

Итак, вот мой быстрый хак (да, я знаю, что он не очень ремонтопригоден и хрупок из-за того, что XML не формируется точно так, как указано) и некоторые результаты:

private void doTest()
{
    Thread t = new Thread()
    {
        public void run()
        {
            runOne(2000);
            runOne(300);
            runOne(20000);
        }

        private void runOne(int num)
        {
            String start = "<DepartmentList>";
            String mid1 =  "<Department>\n" +
                            "<DeptID>";
            String mid2 = "</DeptID>\n" +
                            "<DeptDescription>Dept ";
            String mid3 = "</DeptDescription></Department>";
            String fin = "</DepartmentList>";

            StringBuffer sb = new StringBuffer();
            sb.append(start);
            for (int i=0; i< num; i++)
            {
                sb.append(mid1);
                sb.append(""+i);
                sb.append(mid2);
                sb.append(""+i);
                sb.append(mid3);
            }
            sb.append(fin);

            Pattern p = Pattern.compile(
            "<Department\\s*>\\s*<DeptID\\s*>([^<]*)</DeptID>\\s*<DeptDescription\\s*>([^<]*)</DeptDescription>\\s*</Department>");

            long startN = System.currentTimeMillis();

            DepartmentList d = new DepartmentList();
            List<Department> departments = d.DepartmentList;

            Matcher m = p.matcher(sb);
            while (m.find())
            {
                Department department = new Department();
                department.DeptID(m.group(1));
                department.DeptDescription(m.group(2));
                departments.add(department);
            }

            long endN = System.currentTimeMillis();

            Log.d("Departments", "parsed: " + departments.size() + " in " + (endN-startN) + " millis");
            Log.d("Departments", "lastone: " + departments.get(departments.size() -1)._DeptID + " desc: " + departments.get(departments.size() -1)._DeptDescription);

        }
    };
    t.start();
}

public class DepartmentList {
    public List<Department> DepartmentList =new ArrayList<Department>();
    public boolean FinishedPopulating = false;
}

public class Department {

    private String _DeptID ="";
    public String DeptID()
    {
        return _DeptID;
    }
    public void DeptID(String Value)
    {
        _DeptID = Value;
    }

    private String _DeptDescription ="";
    public String DeptDescription()
    {
        return _DeptDescription;
    }
    public void DeptDescription(String Value)
    {
        _DeptDescription = Value;
    }
}

Я вставил это в проект Android и вызвал его из метода onCreate(). Вот результаты:

Platform        num=300    num=2000     num=20000 
=================================================
Nexus 7         5          38           355
Galaxy Y        29         430          1173
HTC Desire HD   19         189          539
Galaxy Nexus    14         75           379

Все время указано в миллисекундах.

person hack_on    schedule 02.05.2013
comment
В итоге дошли руки попробовать этот метод. Хотя я согласен, что это не самый эффективный метод, у меня есть только 1 таблица данных, которую мне нужно десериализовать таким образом, и это обеспечивает самое быстрое решение. Уменьшено с 6,25 с до ‹3 с. что придется сделать сейчас. Ваше здоровье. - person anothershrubery; 08.05.2013

Для моего исследования это лучший способ оптимизации:

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

Таким образом, рефакторинг вашего кода для использования того же Persister должен улучшить вашу производительность.

Этот и другие советы я получил из этого вопроса. В таком случае этот рефакторинг улучшил производительность, как заявляет автор (с 15 до 3-5 с).

Надеюсь, поможет

person joaonlima    schedule 07.05.2013
comment
Использование того же персистента улучшило производительность, но незначительно. Увеличился с 6,25 до 5,75 с. Разница в 0,5 с не будет иметь большого значения для пользователей, которые все равно будут жаловаться. - person anothershrubery; 08.05.2013

Вы можете исключить промежуточные этапы сериализации (де) путем сериализации непосредственно в XML и десериализации непосредственно из XML, используя, например, JAXB или XStream.

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

public class DeserializeXML implements Runnable {
    private final String xml;
    private final ConcurrentLinkedQueue<Object> deserializedObjects;

    public DeserializeXML(String xml, ConcurrentLinkedQueue deserializedObjects) {
        this.xml = xml;
        this.deserializedObjects = deserializedObjects;
    }

    public void run() {
        deserializedObjects.offer(deserializeXMLToObject(xml, Object.class));
    }
}

// ***

ConcurrentLinkedQueue<String> serializedObjects;
ConcurrentLinkedQueue<Object> deserializedObjects;
ThreadPoolExecutor executor = new ThreadPoolExecutor;
while(!serializedObjects.isEmpty()) {
    executor.execute(new DeserializeXML(serializedObjects.poll(), deserializedObjects));
}
person Zim-Zam O'Pootertoot    schedule 10.04.2013
comment
Десериализация происходит на разовой основе. Когда происходит событие, оно срабатывает и десериализует 1 строку, когда происходит другое, оно десериализует еще одну. Они не хранятся в ConcurrentLinkedQueue, я даже не знаю, где бы я начал разбираться в этом. Я смотрел как на JAXB, так и на XStream, и ни один из них не работал. Один вызывал проблемы с повторяющимися именами пакетов, а другой просто не работал, я не могу вспомнить, в чем именно была проблема. Я рассмотрю их обоих еще раз, но я был бы признателен за ссылку на учебник или рабочий пример для JAXB или XStream, поскольку документация кажется недостаточной. - person anothershrubery; 24.04.2013
comment
Хорошо, после дополнительных исследований ни один из этих пакетов не работает с Android. Я собираюсь поднять награду. - person anothershrubery; 01.05.2013

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

пример:

<node>
  <attr1>value1</attr1>
  <attr2>value2</attr2>
  <attr3>value3</attr3>
  <attr4>value4</attr4>
</node>

был преобразован в

<node attr1='value1'attr2='value2' attr3='value3' attr4='value4' />

Возможно, не лучшее решение с теоретической точки зрения, но улучшение производительности было действительно хорошим. Конечно, если ваш XML немного сложнее (повторяющиеся узлы на разных уровнях или многоуровневые списки), все может быть немного сложнее.

person BigMike    schedule 08.05.2013

Используйте прокси-сервер и преобразуйте свой XML в JSON

person Julian Suarez    schedule 06.05.2013