Posts Tagged asyncTask

Android AsyncTask

My Android Experience

AsyncTask

AysncTask is another way of making some background work without blocking the UI thread. You can also create your own runnable implementation and run it by posting it to the handler. However I find using AsyncTask more simplier.

In my project I wanted to display a ProgressDialog until the screen is filled with data. Data could be fetched from a server or a local database. In order to achieve this task I decided to use AsyncTask. This class  has two important methods ,

protected Result doInBackground(Params… params)

where all the background operations should be made whitin this method but you can not make any UI updates.

and

protected void onPostExecute(Result result)

where the UI could be updated according to the result of the background operation.

What I needed was a some kind of AsyncTask which displays a ProgressDialog until the background operation is finished and when onPostExecute method is called it would dismiss the dialog. When you think like that it looks very simple.

Creating a progressDialog in the constructor and displaying it immediately and dismissing it in onPostExecute method. Unfortunately this didnt work because UI thread was blocked by the ProgessDialog, it was tied to it and that’s why it wasn’t possible to dismiss the dialog. Finally I came up with another idea. First I created another class “ProgressTimedTask” which extends AsyncTask. It has a progressDialog as a member field. The source code looks like this.

//this is an abstract class which basically does nothing but works as a template for other task classes
public abstract class ProgressTimedTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
private ProgressDialog dialog;

public void showWarningMessage() {
Toast.makeText(dialog.getContext(), "Sorry but no response from the server, why dont you try again later!",
Toast.LENGTH_LONG).show();
}

public final void dismiss() {
cancel(true);
dialog.dismiss();
}

@Override
protected final void onPostExecute(Result result) {
super.onPostExecute(result);
runOnPostExecute(result);
dialog.dismiss();
}

protected void runOnPostExecute(Result result) {
// delegate method
}

@Override
protected final Result doInBackground(Params... params) {
return runInBackground(params);
}

protected abstract Result runInBackground(Params... params);

public final void setDialog(ProgressDialog dialog) {
this.dialog = dialog;
}

public final void showProgressDialog() {
 if (this.dialog != null) {
    this.dialog.show();
  }
 }
}

As you can see the methods overridden from AsyncTask class are marked as final as I don’t want sub classes of this ProgessTimedTask class to override these methods. I wanted this class to act as a template and I wanted to keep the control of the ProgressDialog’s lifecycle within that class, that’s why it cannot be accessed from outside. And here is a class which extends ProgessTimedTask .

public class BasicTimedTask extends ProgressTimedTask<Void, Void, Void> {

private DelegateTaskActivity<Void, Void> delegateTaskActivity;

private BasicTimedTask(DelegateTaskActivity<Void, Void> delegateTaskActivity) {
    this.delegateTaskActivity = delegateTaskActivity;
}

@Override
protected Void runInBackground(Void... xxx) {
    return delegateTaskActivity.getData(xxx);
}

@Override
protected void runOnPostExecute(Void x) {
   delegateTaskActivity.updateUI(x);
 }
}

Here DelegateTaskActivity is an interface, I assumed that the class which instantiates BasicTimedTask should also provide the class which does the background job and update the UI. in my example this class is the activity class, simply whenever I want to display a ProgressDialog in my activity while fetching data from somewhere , my activity class implements DelegateTaskActivity.

And now it’s time to create an instance of this BasicTimedTask class. Here how I do it …

ProgressDialog progressDialog = new ProgressDialog(context);
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.setMessage("Loading ... ");
progressDialog.setIndeterminate(true);
progressDialog.setCancelable(true);

ProgressTimedTask<Params, Progress, Result> timedTask = new BasicTimedTask(delegateTaskActivity);
timedTask.setDialog(progressDialog);
timedTask.showProgressDialog();

As you can see before executing the task I called showProgressDialog() method which displays the progress dialog.I also wanted to add a timeout functionality so that after certain amount of time the task will stop executing and null result will be returned. In order to do that I needed a Future task which will be responsible of executing the timedTask. Here is the source code of FutureTask

final FutureTask<Void> futureTask = new FutureTask<Void>(new Runnable() {

@Override
public void run() {
task.execute(params);
try {
task.get();
} catch (InterruptedException e) {
task.cancel(true);
} catch (ExecutionException e) {
task.cancel(true);
} catch (CancellationException e) {
task.cancel(true);
}
}
}, null);

Because I dont want to block the UI thread here is the trick. This future task will be executed by another thread and if the timeout occurs then the message is displayed to the users. It seems a bit complicated but certainly it works! Here is the last bit of the code

Runnable r = new Runnable() {

			@Override
			public void run() {
				boolean timeout = false;
				try {

					Executors.newSingleThreadExecutor().execute(futureTask);
					futureTask.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
				} catch (InterruptedException e) {
					Log.d(TAG, "InterruptedException dismissing the task", e);
				} catch (ExecutionException e) {
					Log.d(TAG, "ExecutionException dismissing the task", e);
				} catch (TimeoutException e) {
					Log.d(TAG, "TimeoutException dismissing the task", e);
					timeout = true;
				} catch (CancellationException e) {
					Log.d(TAG, "CancellationException dismissing the task", e);
				} finally {
					task.dismiss();
					if (timeout && showWarningMessage) {
						handler.post(new Runnable() {
							@Override
							public void run() {
								task.showWarningMessage();
							}
						});

					}

				}

			}
		};

		Executors.newSingleThreadExecutor().execute(r);

Leave a Comment