Android speed error with deserialization using SimpleXML

Raised generosity as the only answer did not provide a good implementation for Android. Is there a faster implementation compatible with Android? Or is SimpleXML the best performance I get?

I am new to Java and Android, so I don’t know the correct procedure for deserializing the xml string for an object. 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 string (misnamed) xml and objClass is the empty class of the class I want to deserialize to. This is usually a list of other objects.

Class Example:

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

XML example:

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

This works great throughout the application, but I have come to the conclusion that it needs to deserialize> 300 objects in the list. It takes about 5 seconds or close to a minute when debugging, but users are not happy with this performance and wasted time when debugging is undesirable. Is there any way to speed this up? Or should I do it differently? Preferably only by changing the deserializeXMLToObject method.

+4
source share
5 answers

I'm sure someone will point to the best library that is there, but according to one detailed answer , they are all slow on Android.

So, here is my quick hack (yes, I know that it is not very user-friendly and fragile so that the XML is not generated exactly as indicated) and some results:

 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 put this into an Android project and called it the onCreate () method. Here are 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 

Time in milliseconds.

+6
source

For my research, this is the best way to optimize:

"Simple dynamic layout of object graphs, which means that to load classes that have not yet been loaded, you will need to create a diagram for each class based on its annotations. Therefore, the first use will always be the most expensive. Reusing the same instance of persister will many times faster. So try to avoid multiple instances of persister, just use one if possible. "

So refactoring your code to use the same Persister should improve your performance.

These are other tips I received from this question . In this case, this refactoring improved productivity, as the author stated (from 15 to 3-5 years).

Hope this helps

+3
source

You can eliminate the steps of intermediate (de) serialization by serializing directly into XML and deserializing directly from XML using, for example, JAXB or XStream .

You can also speed things up through multithreading. I assume that all the XML strings you want to deserialize are in ConcurrentLinkedQueue ; alternatively, you can synchronize access to any non-threading collection that you are using. Use something like ThreadPoolExecutor to minimize thread creation costs.

 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)); } 
+2
source

Got a similar issue with SOAP web service once ago. In the end, I changed the XML format, converting the nodes into attributes.

Example:

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

has been converted to

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

Perhaps not the best solution is theoretically wise, but the performance improvement was really good. Ofc, if your XML is a little more complicated (duplicate nodes at different levels or multi-level lists), everything can be a little complicated.

0
source

Use server proxy and convert XML to JSON

-1
source

All Articles