5

My AsyncTask is blocking block button element while downloading image and progress dialog is shown with delay - its shows for a while before image is shown, but downloading takes long time and button is blocked (orange) and dialog is not shown.

 public  Bitmap download(String url, ProgressBar progressbar) throws InterruptedException, ExecutionException {
     BitmapDownloaderTask task = new BitmapDownloaderTask(progressbar);
     task.execute(url);
     return task.get();
}

class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {



    public BitmapDownloaderTask(ProgressBar progressbar) {

    }
    @Override
    protected void onPreExecute() {
        dialog = new ProgressDialog(ShowActivity.this);
        dialog.setMessage("Loading");
        dialog.setIndeterminate(true);
        dialog.setCancelable(false);
        dialog.show();
    }

    @Override
    protected Bitmap doInBackground(String... Params) {
        return imageLoader.getBitmap(params[0]);

    }
    @Override
    protected void onPostExecute(Bitmap bitmap) {
         dialog.dismiss();


    }
}    

In button listener, simply call download function, the progress parameter is because I have progress bar circle in imageview - the dialog is for testing only, to found why is there the delay and block. In another app I use runable and thread and element is not blocked, but in tutorials is AsyncTask mentioned as better solution for this.

Peter O.
  • 32,158
  • 14
  • 82
  • 96
Dupla
  • 65
  • 2
  • 8
  • this is the right way to do it, check this link :http://www.android-ios-tutorials.com/182/show-progressbar-while-downloading-image-using-asynctask-in-android/ – Houcine Sep 16 '14 at 17:25

3 Answers3

13

The image download is indeed executed in the background thread, but with return task.get(); you're just waiting for it to finish, and that's what's blocking your main thread.

You should use onPostExecute() as a callback for when the task has finished, so not just to dismiss the dialog but also to do what you need with the bitmap returned by doInBackground().

bigstones
  • 15,087
  • 7
  • 65
  • 82
2

It is because you are calling AsyncTask#get:

Waits if necessary for the computation to complete, and then retrieves its result.

You should perform whatever operation you need to use the image for within onPostExecute()

dave.c
  • 10,910
  • 5
  • 39
  • 62
  • That description, straight from the Android documentation, could be a bit clearer that "wait" is meant in a very technical sense where "nothing can happen in the calling thread, e.g., UI updates." – John Perry Aug 11 '17 at 08:32
0

Old question, but have facing this issue. Yes, AsyncTask.get will block the UI thread until the result arrive, not giving processing space for your dialog to show, I've faced the same problem resolving with a more generic solution. Basically I create my AsyncTasks with a constructor receiving an AsyncTaskData (AsyncTaskData is a class that I have created, it's bellow) with all necessary data and a callback. I leave you my classes and an example.

AsyncTaskData.java

public class AsyncTaskData {

    private Context activityContext;
    private Object inputData; // whatever you want
    private AsyncTaskCallback callback;

    public AsyncTaskData(Context activityContext, Object inputData, AsyncTaskCallback callback) {
        this.activityContext = activityContext;
        this.inputData = inputData;
        this.callback = callback;
    }

    // getters and setters
}

AsyncTaskCallback.java

public interface AsyncTaskCallback {
    // method to be called when the task is finished (onPostExecute)
    void onAsyncTaskTerminated(Object result);
}

So, for instance, if I have an AsyncTask to make login, it will be declared as follow:

public class LoginAsyncTask extends AsyncTask<Void, Void, Boolean> {

    private AsyncTaskData asyncTaskData;
    private ProgressDialog progressDialog;

    public LoginAsyncTask (AsyncTaskData asyncTaskData) {
        this.asyncTaskData = asyncTaskData;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();

        progressDialog = new ProgressDialog(asyncTaskData.getActivityContext(), R.style.AppTheme);
        progressDialog.show();
    }

    @Override
    protected Boolean doInBackground(Void... voids) {
        // if needed, get your data with asyncTaskData.getInputData()
        AuthenticationData authData = (AuthenticationData) asyncTaskData.getInputData();
        boolean loggedIn = // your heavy authentication process goes here
        return loggedIn;
    }

    @Override
    protected void onPostExecute(Boolean loggedIn) {
        super.onPostExecute(searchResponse);

        progressDialog.dismiss();

        if(asyncTaskData.getCallback() == null) return;

        asyncTaskData.getCallback().onAsyncTaskTerminated(loggedIn);
    }
}

Finally, to use it just do this in your Fragment/Activity:

AsyncTaskData asyncTaskData = new AsyncTaskData(
    getActivity(), // or this if you are calling from an Activity
    new AuthenticationData("username", "password"), 
    result -> {
        boolean loggedIn = (boolean) result;
        // your login logic goeas here
    });

new SearchAsyncTask(asyncTaskData)
    .execute();

After many approaches, I ended up using this one because it's generic, leave the code clean and solve the problem of caling .get() method and blocking UI thread. Hope it helps.

rmpt
  • 606
  • 1
  • 4
  • 24