I've written a XML-Parser in Java using the SAXParserFactory (Code below). On my laptop it needs <1 second, but on my Android phone (S3 mini) it takes around 30seconds for the same file.
It parses a list of collectible cards. The xml-File is ~5MB and while parsing I create ~15000 Card Objects, which only contain Strings and are stored in a HashMap. When finished the App requires ~6MB RAM.
Using logcat I noticed that the GC is called quite often I think. I get the following output ~200 times:
02-05 16:03:51.460 21736-21738/magic.icebrothers.de.magicsimulatorandroid D/dalvikvm﹕ GC_CONCURRENT freed 704K, 15% free 11791K/13844K, paused 3ms+3ms, total 108ms
02-05 16:03:51.460 21736-21749/magic.icebrothers.de.magicsimulatorandroid D/dalvikvm﹕ WAIT_FOR_CONCURRENT_GC blocked 45ms
Is there a possibility to speed this up, by eg. using another XML-Parser, or using another data structure?
Or does it simply take so long to allocate the memory for this many objects?
I have tried to serialize the HashMap, but even loading this takes almost the same time (~25sec).
Thanks in advance!
private static class CardHandler extends DefaultHandler {
private Card transform = null;
private Card currentCard = null;
private String currentElement = null;
private HashMap<String, String> currentAttributes;
public CardHandler() {
currentAttributes = new HashMap<>();
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
super.characters(ch, start, length);
String characters = new String(ch, start, length);
if (!characters.trim().isEmpty() && currentElement != null && currentCard != null) {
switch (currentElement) {
case "name":
currentCard.setName(characters);
cards.put(characters, currentCard);
break;
case "cost":
currentCard.setCost(characters);
break;
case "type":
switch (currentAttributes.get("type")) {
case "card":
currentCard.addCardType(characters);
break;
case "sub":
currentCard.addSubType(characters);
break;
case "super":
currentCard.addSuperType(characters);
break;
}
break;
case "rule":
int no = 1;
try {
no = Integer.parseInt(currentAttributes.get("no"));
} catch (NumberFormatException ex) {
}
String reminder = null;
if (currentAttributes.get("reminder") != null) {
reminder = currentAttributes.get("reminder");
}
currentCard.addRule(no, reminder, characters);
break;
}
}
}
@Override
public void endElement(String uri, String localName, String name)
throws SAXException {
super.endElement(uri, localName, name);
currentElement = null;
}
@Override
public void startDocument() throws SAXException {
super.startDocument();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
currentElement = qName;
for (int i = 0; i < attributes.getLength(); i++) {
currentAttributes.put(attributes.getQName(i), attributes.getValue(i));
}
switch (currentElement) {
case "card":
currentCard = new Card();
break;
}
}
}