Friday, October 12, 2018

Tips for creating progress bar when loading two or more async tasks in Android

keyword: android, progress bar, async, tasks, background, thread

In a situation where we need to make multiple async tasks such as in the situation when an activity needs to make multiple recycles views (or fragments), we can reuse same spinning progress bar widget until all of the async tasks have been completed. The async calls can be used for loading data over network or database or smoother long-running tasks. Since the async tasks are happening in the background thread, attempting to start the spinner from the main thread and closing the spinner from background thread would result into the exception of type "CalledFromWrongThreadException" which implies that only the original thread that created a view hierarchy can touch its views.

This can be accomplished by creating two variables, one to store a number of requests made and another to store the number of requests completed. The assumption is that the async task is an inner class of the calling class. The number of requests made is increment before calling the async task. And a number of requests completed are incremented onPostExecute function of the async class. The progress bar is initialized in the calling class. The progress bar's visibility is set to visible on the start of the async class. The progress bar's visibility is hidden after onPost execute and only if the number of requests made is equal to the number of requests completed. Simple !.

Below I am outlining some major steps. I am hoping I would expand this article to add more details in the future with full working code.

Defined two private variables to do a count of async tasks in the activity that calls the async tasks. One counter tracks tasks have been requested and other is for how many have been finished.

     private int AsyncTaskCount = 0; //tracks number of requests completed
     private int AsyncTaskRequested = 0; //tracks number of requests
     private ProgressBar spinner; //defined the progressBar

Initialized the progress bar onCreate method of the calling class.

    spinner = (ProgressBar)findViewById(R.id.progressbar);


Update the count of requested say prior to calling the asynctask:

       AsyncTaskRequested = 2; //we are requesting two asynctasks
       new NetworkQueryTask().execute(SmartStockConstant.QueryMarket);
       new NetworkQueryTask().execute(SmartStockConstant.QueryStock);

On the asynctask, update the AsyncTaskCount in the doInBackground and set the progress bar visible:

    class NetworkQueryTask extends AsyncTask<String, Void, ArrayList<Stock>> {
            private String query;
            @Override
            protected ArrayList<Stock> doInBackground(String... params) {
                AsyncTaskCount++; //track the executed
                spinner.setVisibility(View.VISIBLE); //set the bar visible

Finally, onPostExecute, check if the number of completed task equals the number of requested and make the progress bar invisible

    @Override
    protected void onPostExecute(ArrayList<Stock> searchResults) {
                super.onPostExecute(searchResults);
    //main logic here
         if(AsyncTaskCount == AsyncTaskRequested) {
             spinner.setVisibility(View.GONE);
         }
   
   
    }