简体   繁体   English

使用SimpleXML进行反序列化的Android速度问题

[英]Android speed issue with deserialization using SimpleXML

Raised a bounty as the only answer doesn't provide a good implementation for Android. 提出了赏金,因为唯一的答案并没有为Android提供良好的实现。 Is there a speedier implementation compatible with Android? 是否有与Android兼容的更快速的实现? Or is SimpleXML the best performance I'll get? 或者SimpleXML是我得到的最佳性能?

I'm fairly novice to Java and Android development so don't know the proper procedure for deserializing an xml string to an object. 我是Java和Android开发的新手,因此不知道将xml字符串反序列化为对象的正确过程。 I found a method that works in: 我发现了一种适用于的方法:

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;
    }
}

Where xmlFile is the (misnamed) xml string, and objClass is an empty class of the class I want to deserialize to. 其中xmlFile是(错误命名的)xml字符串,而objClass是我要反序列化的类的空类。 This is generally a list of other objects. 这通常是其他对象的列表。

Example class: 示例类:

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

Department class: 系类:

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;
    }
}

Example XML: 示例XML:

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

This has been working fine throughout the app, but I have come to a point where it needs to deserialise >300 objects in the list. 这在整个应用程序中都运行良好,但我已经到了需要在列表中反序列化> 300个对象的点。 This only takes approximately 5 secs, or close to a minute when debugging, but users are not happy with that performance and time wasted when debugging isn't desirable. 这只需要大约5秒,或者在调试时接近一分钟,但是当不希望进行调试时,用户对该性能和浪费的时间不满意。 Is there any way to speed this up? 有什么方法可以加快速度吗? Or is there another way I should be doing this? 或者我还有另一种方法吗? Preferably only by changing the deserializeXMLToObject method. 最好只通过改变deserializeXMLToObject方法。

I am sure someone will point to a better library that's out there, but according to one detailed answer , they are all slow on Android. 我相信有人会指出一个更好的图书馆,但根据一个详细的答案 ,他们在Android上都很慢。

So here is my quick hack (yes I know its not very maintainable and is brittle to the XML not being formed exactly as specified) and some results: 所以这是我的快速黑客(是的,我知道它不是非常可维护,并且对于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;
    }
}

I pasted this into an Android project and called it from the onCreate() method. 我将其粘贴到Android项目中,并从onCreate()方法调用它。 Here is the results: 结果如下:

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

All times are in milliseconds. 所有时间都以毫秒为单位。

For my research this is the best way to optimize: 对于我的研究,这是优化的最佳方式:

"Simple will dynamically build your object graph, this means that it will need to load classes that have not already been loaded, and build a schema for each class based on its annotations using reflection. So first use will always be by far the most expensive. Repeated use of the same persister instance will be many times faster. So try to avoid multiple persister instances, just use one if possible." “Simple会动态构建你的对象图,这意味着它需要加载尚未加载的类,并使用反射基于其注释为每个类构建一个模式。所以首次使用将始终是最昂贵的重复使用相同的persister实例会快很多倍。所以尽量避免多个persister实例,如果可能的话只使用一个。“

So refactoring your code to use the same Persister should improve you performance. 因此,重构代码以使用相同的Persister可以提高性能。

This and other tips I got from this question . 我从这个问题得到的这个和其他提示。 In that case, this refactoring improved the performance, as stated by the author (from 15s to 3-5s). 在这种情况下,这种重构改进了性能,如作者所述(从15s到3-5s)。

Hope it helps 希望能帮助到你

You can eliminate the intermediate (de)serialization steps by serializing directly to XML and deserializing directly from XML, using eg JAXB or XStream . 您可以通过直接序列化为XML并直接从XML反序列化来消除中间(反)序列化步骤,例如使用JAXBXStream

You may also be able to speed things up via multithreading. 您也可以通过多线程加快速度。 I'll assume that all of the XML strings you want to deserialize are in a ConcurrentLinkedQueue ; 我假设您要反序列化的所有XML字符串都在ConcurrentLinkedQueue中 ; alternatively, you can synchronize access to whatever non-threadsafe collection you're using. 或者,您可以同步访问您正在使用的任何非线程安全集合。 Use something like a ThreadPoolExecutor to minimize thread creation overhead. 使用类似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));
}

Got a similar issue with a SOAP Web Service times ago. 很久以前,SOAP Web服务遇到了类似的问题。 In the end I've changed the format of the XML, transforming the nodes in attributes. 最后,我改变了XML的格式,转换了属性中的节点。

example: 例:

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

was transformed in 被改造了

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

Maybe not the best solution theorically wise, but performance improvement was really good. 也许不是理论上最好的解决方案,但性能提升确实很好。 Ofc if your XML is a bit more complex (repeteable nodes at various levels or multi level lists) things may be a bit complex. 如果你的XML有点复杂(在各个级别或多级列表中可重复的节点),事情可能有点复杂。

使用服务器代理并将XML转换为JSON

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM