My application makes a HTTP request to retrieve an XML file and then translates that into a ListView.
The problem is that when the View containing that list is opened the app freezes for a few seconds while the content is downloaded and parsed and translated onto the ListView. (But it works).
I have tried to implement an AsyncTask (see code below) to do the processing in a background thread, but my implementation has caused the app the freeze for a much longer time than before.
This involves three classes: MainActivity class; ListViewer class; and XMLhelper class. MainActivity just contains a Button to call the ListViewer. ListViewer is supposed to be the UI thread. XMLhelper contains functions to make the HttpClient request.
ListViewer.java (brief):
public class ListViewer extends ListActivity {
private ArrayList<HashMap<String, String>> xmlList;
private String server;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_view);
xmlList = new ArrayList<HashMap<String, String>>();
server = "http://www.myserver.com/xml";
getXMLList();
}
public void getXMLList() {
Document xmlDocument = XMLhelper.getXMLDocument(server);
int numResults = XMLfunctions.numResults(xmlDocument);
if (numResults <= 0) {
Toast.makeText(this, "No results found.", Toast.LENGTH_LONG).show();
finish();
}
NodeList nodes = xmlDocument.getElementsByTagName("result");
for (int i=0; i<nodes.getLength(); i++) {
HashMap<String, String> map = new HashMap<String, String>();
Element e = (Element)nodes.item(i);
map.put(...); //code omitted
xmlList.add(map);
}
ListAdapter adapter = new SimpleAdapter(this, xmlList,
R.layout.list_view_row,
new String[] {...},
new int[] {...});
setListAdapter(adapter);
}
}
XMLhelper.java (brief):
public class XMLhelper {
public static class DownloadContentTask extends AsyncTask<String, Void, String> {
DownloadContentTask(String... URLs) {
this.execute(URLs);
}
@Override
protected String doInBackground(String... URLs) {
String xml = null;
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(URLs[0]);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
xml = EntityUtils.toString(httpEntity);
} catch (...) {
xml = "..."; //all exceptions are caught
}
return xml;
}
}
public static Document getXMLDocument(String server) {
DownloadContentTask xmlTask = new DownloadContentTask(new String[] { server });
String xml = "";
try {
xml = xmlTask.get();
} catch (...) {
//print errors
}
return XMLfromString(xml);
}
public static Document XMLfromString(String xml) { ... }
public final static String getElementValue(Node elem) { ... }
public static int numResults(Document doc) { ... }
public static String getValue(Element item, String str) { ... }
}
I intended to make it so that when ListViewer is called from the MainActivity the ListView is unpopulated but the UI is shown immediately, and then as soon as the content is downloaded and parsed the ListView is updated.
What am I doing wrong?
Pretty simple, take a look at the
get()method documentation:By calling
get()ingetXMLDocumentyou block the current thread (UI Thread) untill the async task is done.The async task should do the updates itself, invoke them in the UI thread, rather than return the information back to the caller from UI thread.
And you should always read the documentation 😉