Search code examples
androidandroid-asynctaskprogress-barhandlerasync-onprogressupdate

Show determinate ProgressBar in onProgressUpdate of AsyncTask during the time taken to download data from the internet


I am trying to use this library to publish progress on the Activity screen in the onProgressUpdate() of an AsyncTask, which is used to download some data from the internet. The demo application they have provided is using Handler to demonstrate this. I need to use it in an AsyncTask.

Following code snippet is from the code in their demo application.

My questions are:

  1. onProgressUpdate gets an argument Progress... values, and according to the documentation, it is "the values indicating progress." But I don't understand what this means, and how to I use this argument. In the examples I have seen, they are doing something like:

    progressBar.setProgress(Integer.parseInt(values[0]));
    

    Why are they using only the first value in the passed array (values[0])?

  2. How does the AsyncTask know how long is it going to take to finish the download operation. I want to show the ProgressBar progress from value 0 to 100 during the time spent to finish the download operation.

    By doing progressBarDeterminate.setVisibility(View.VISIBLE) in onPreExecute and doing progressBarDeterminate.setVisibility(View.GONE) in onPostExecute, we are ensuring that it only shows when the data is being downloaded, but how to we ensure that it progresses from starting position to final position during the time it takes to download the data (when we don't know precisely how long is it going to take to download the data) ?

CODE FROM DEMO EXAMPLE (It uses Handler, but I need to do this in AsyncTask)

public class MainActivity extends AppCompatActivity {
    ProgressBarDeterminate progressBarDeterminate;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        progressBarDeterminate = (ProgressBarDeterminate) findViewById(R.id.progressDeterminate);

        progressTimer.start();
    }


        Thread progressTimer = new Thread(new Runnable() {

                @Override
                public void run() {
                    for(int i = 0; i <= 100; i++){
                        try {
                            Thread.sleep(30);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        handler.sendMessage(new Message());
                    }
                }
            });

            Handler handler = new Handler(new Handler.Callback() {
                int progress = 0;
                @Override
                public boolean handleMessage(Message msg) {
                    progressBarDeterminate.setProgress(progress++);
                    return false;
                }
            });
}

Solution

  • In answer to your first question, onProgressUpdate() takes a varargs argument. This means that it can take an indefinite number of arguments of the specified type. For example:

    public void someMethod(String... args) {
        //...
    }
    

    Could be called either like this, someMethod("Hi!"), or this someMethod("Hi", "there", "welcome", "to", "SO").

    More on varargs can be found here. These arguments are accessed in the same way as you would an array. If there is only one argument there, then you could use args[0].

    Edit: In regards to your second question, as good an example as any is present in the Android Developers javadocs:

    private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
         protected Long doInBackground(URL... urls) {
             int count = urls.length;
             long totalSize = 0;
             for (int i = 0; i < count; i++) {
                 totalSize += Downloader.downloadFile(urls[i]);
                 publishProgress((int) ((i / (float) count) * 100));
                 // Escape early if cancel() is called
                 if (isCancelled()) break;
             }
             return totalSize;
         }
    
         protected void onProgressUpdate(Integer... progress) {
             setProgressPercent(progress[0]);
         }
    
         protected void onPostExecute(Long result) {
             showDialog("Downloaded " + result + " bytes");
         }
     }
    

    Namely, the answer really depends on your circumstances. Say in the above example that you need to download ten URLs. A for loop is set-up to download each URL sequentially, and once that URL has finished, publishProgress() is called, turning the current value into a percentage figure, (i / (float) count) * 100). Hopefully that answers your question!