1

I have an android app, written in java which uses AsyncTask to download data. The AsyncTask is needed to handle the progress dialog box which is shown throughout the download.

The actual download is initiated through a separate thread, downloadAllUpdater. Whilst I am aware this is not convention, a thread is required as the process of downloading is spread across 7 classes and there was no other way to update the progress bar whilst the download was occurring as I couldn't run the publishProgress call from any other class.

My main activity is shown below:

private Download downloadAll;

private int totalBlocksLeft;

private boolean downloadComplete;
private boolean downloadFailed;

private PerformTask currentPerformTask;

public void downloadAllClick(View view) //When the download all button is clicked
{
    currentPerformTask = new PerformTask();

    currentPerformTask.execute();
}

private class PerformTask extends AsyncTask<Void, Integer, Integer>
{
    protected void onPreExecute()
    {
        usingDialog = new ProgressDialog(WifiAudioActivity.this);

        usingDialog.show();
    }

    protected Integer doInBackground(Void... voi) 
    {
        downloadAll = new Download();

        downloadComplete = false;   //Assume the download is not complete

        downloadAllUpdater.start(); 

        downloadFailed = false;

        while ((downloadComplete == false) && (downloadFailed == false))   
        {
            blocksDownloaded = downloadAll.getTotalBlocksLeft();

            publishProgress(blocksDownloaded);
        }

        return 0;
    }

    protected void onProgressUpdate(Integer... progress) 
    {
        usingDialog.setProgress(progress[0]);
    }

    protected void onPostExecute(Integer result) 
    {
        usingDialog.dismiss();
    }
}

Thread downloadAllUpdater = new Thread()
{
    public void run() 
    {
        int runRetryCount = 0;

        while ((!(downloadComplete)) && (!(downloadFailed)))
        {
            downloadComplete = download.downloadAudio(totalBlocksLeft);  //Download the audio

            if (!(downloadComplete))
            {
                runRetryCount++;
            }

            if (runRetryCount > Consts.RETRY_TOTAL)
            {
                downloadFailed = true;
            }
        }
    }
};

The download is initiated with the click of the button, which initiates the downloadAllClick() method.

This all works fine the first time the button is pressed.

However, when the button is pressed a second time (after the first time completition), I receive an error and the program force closes.

I am pretty sure the error is because I am running the Thread, downloadAllUpdater a second time, because if I have a separate method with just downloadAllUpdater.start(), it also crashes with the same error.

Can anyone help? Below is the error log:

08-23 11:22:34.954: W/dalvikvm(1485): threadid=14: thread exiting with uncaught exception (group=0x400259f8)

08-23 11:22:35.014: E/AndroidRuntime(1485): FATAL EXCEPTION: AsyncTask #5

08-23 11:22:35.014: E/AndroidRuntime(1485): java.lang.RuntimeException: An error occured while executing doInBackground()

08-23 11:22:35.014: E/AndroidRuntime(1485):     at android.os.AsyncTask$3.done(AsyncTask.java:200)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.util.concurrent.FutureTask.setException(FutureTask.java:124)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.util.concurrent.FutureTask.run(FutureTask.java:137)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.lang.Thread.run(Thread.java:1102)

08-23 11:22:35.014: E/AndroidRuntime(1485): Caused by: java.lang.IllegalThreadStateException: Thread already started.

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.lang.Thread.start(Thread.java:1331)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at com.que.wifiaudio.WifiAudioActivity$PerformTask.doInBackground(WifiAudioActivity.java:518)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at com.que.wifiaudio.WifiAudioActivity$PerformTask.doInBackground(WifiAudioActivity.java:1)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at android.os.AsyncTask$2.call(AsyncTask.java:185)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)

08-23 11:22:35.014: E/AndroidRuntime(1485):     ... 4 more
tshepang
  • 12,111
  • 21
  • 91
  • 136
Pippa Rose Smith
  • 1,377
  • 5
  • 18
  • 42

3 Answers3

2

You can't start a Thread twice. You could make downloadAllUpdater a Runnable instead:

Runnable downloadAllUpdater = new Runnable() { //rest unchanged

And replace the code in doInBackground with:

new Thread(downloadAllUpdater).start();

That way, a new thread is created every time, running the same task.

However doInBackground is already running on a background thread, are you sure you need to create a new thread? If not, just run the runnable: downloadAllUpdater.run(); without creating a new thread.

assylias
  • 321,522
  • 82
  • 660
  • 783
  • sorry, neither seem to work. If I try the new Thread(downloadAllUpdater).start();, it gives the same error and the downloadAllUpdater.run() doesn't update the progress bar. – Pippa Rose Smith Aug 23 '12 at 12:11
  • You should not get the same error if you have made `downloadUpdater` a Runnable and start a new thread each time, maybe a different error? Also, all the variables that you share across threads (`downloadComplete`, `totalBlocksLeft` and `downloadFailed`) should be volatile. – assylias Aug 23 '12 at 12:18
  • It's definitely the same error, exactly - evidently it isn't the thread? I'll make the variables volatile, just incase that helps. – Pippa Rose Smith Aug 23 '12 at 12:40
  • Ok, I can't have updated the code properly. You're right, it now doesn't throw the error the second time round, but the thread doesn't restart. – Pippa Rose Smith Aug 23 '12 at 13:39
  • Either `start` is called and it does start again or it is not called. You should add some logs in your code to better understand what gets executed and when. – assylias Aug 23 '12 at 13:40
1

Not sure if this is related to the error you're seeing, but your current code is not thread safe. You're currently assigning the member variables downloadComplete and downloadFailed from two different threads (PerformTask and downloadAllUpdater). This usage will lead to race conditions and unexpected results. Please read about the concurrency in Java (namely, the synchronized keyword), to synchronize your threads.

Finer Recliner
  • 1,579
  • 1
  • 13
  • 21
0
runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        // TODO Auto-generated method stub

                        //do you download here

                    }
                });

within Asyctask you cannot access stuff happening in a different theread

Srikanth Pai
  • 926
  • 3
  • 17
  • 30