Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android speed issue with deserialization using SimpleXML

Raised a bounty as the only answer doesn't provide a good implementation for Android. Is there a speedier implementation compatible with Android? Or is SimpleXML the best performance I'll get?

I'm fairly novice to Java and Android development so don't know the proper procedure for deserializing an xml string to 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 (misnamed) xml string, and objClass is an empty class of the class I want to deserialize to. 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:

<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. 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. 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.

like image 319
anothershrubery Avatar asked Dec 27 '22 05:12

anothershrubery


1 Answers

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.

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:

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. 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.

like image 74
hack_on Avatar answered Jan 01 '23 04:01

hack_on