Reputation: 124
I am developing a simple application for Android, and have just tried to switch to using an asynctask to to the FTP call and XML parsing that the app requires (it's a weather app FYI).
Unfortunately I started to notice very odd behaviour in my app. I debugged, and discovered to my horror that the code within the doInBackground() method was executing out of order!
The code below is simplified (catch statements rolled up ect) for brevity, however none of the essentials are changed. The asynctask is called in onResume(), and it then makes a call to the ftp server, downloads the file, and then parses it. What is occurring (which I can see very clearly via the debug statements you can see below), is that the parsing call is being made before the file download is complete. So, in terms of the debug statements, the order is often:
I am more than happy to provide more code (all of it if need be!), and answer any questions anyone might have.
@Override
public void onResume()
{
if(!inOnResume)
{
inOnResume = true;
super.onResume();
File file = new File(getFilesDir(), selectedCity);
new GetBOMWeatherData().execute(file);
}
}
private class GetBOMWeatherData extends AsyncTask<File, Void, Void>
{
boolean fileDownloaded = false;
@Override
protected void onPreExecute()
{
showDialog(PROGRESS_KEY);
super.onPreExecute();
}
@Override
protected Void doInBackground(File... params)
{
FileOutputStream fos = null;
try
{
fos = new FileOutputStream(params[0]);
}
catch (FileNotFoundException e)
{
Log.e("ApiException", "There was an error opening the file output stream.", e);
cancel(false);
}
try
{
Log.d("Before get file", "Before get file");
DataRetriever.getPageContent(selectedCity, fos);
Log.d("After get file", "After get file");
fileDownloaded = true;
}
catch (ApiException e)
{
Log.d("After get file with error", "After get file with error");
Log.e("ApiException", "There was an error opening the file output stream.", e);
cancel(false);
}
finally
{
Log.d("After get file finally", "After get file finally");
}
try
{
Log.d("Before parse file", "Before parse file");
forecasts = parseXML(selectedCity);
Log.d("After parse file", "After parse file");
lastDownloaded.put(selectedCity, new Date());
}
catch (FactoryConfigurationError e)
{
Log.d("After parse file with error", "After parse file with error");
Log.e("XMLParsingException", "There was an error in the factory configuration.", e);
cancel(false);
}
finally
{
Log.d("After parse file finally", "After parse file finally");
}
return null;
}
@Override
protected void onPostExecute(Void file)
{
inOnResume = false;
super.onPostExecute(file);
dismissDialog(PROGRESS_KEY);
updateView();
}
@Override
protected void onCancelled()
{
super.onCancelled();
showDialog(FAILURE_KEY);
}
}
Edit: the reason I descovered that it was executing out of order was that odd errors started to occur. If I run everything in the main UI thread it works, however as soon as I put it all in an asynctask I get XML parse errors. The issue appears to be that the file is not fully downloaded when my app tries to parse it.
Upvotes: 0
Views: 906
Reputation: 175
DataRetriever.getPageContent(selectedCity, fos);
This is executed in another thread, and it's not blocking. So it's perfectly normal that it crashes here and not in main thread. Do not use this.
SAXParser parseur = SAXParserFactory.newInstance().newSAXParser();
parseur.parse(uri, DefaultHandler);
// On récupère directement la liste des feeds
ArrayList<Object> entries = ((DefaultHandler) handler).getData();
This is of course only if you don't save the XML file to the memory. Then you just have to do the parsing in a class that implements DefaultHandler.
See the doc for further info.
Regards
Upvotes: 0
Reputation: 6317
You're probably ending up with more than one thread running. You're seeing the parsing log from the previous one finishing and then the new one is entering the download. Since you probably only want one at a time, you'll need to use some kind of locking to prevent two from running at the same time.
Upvotes: 1