chesterm8
chesterm8

Reputation: 124

Potential bug in android's asynctask

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:

  1. Before get file
  2. Before parse file
  3. After parse file with error (as the file has not downloaded yet!)
  4. After get file

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

Answers (2)

Nabil Gardon
Nabil Gardon

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

JOTN
JOTN

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

Related Questions