Tuesday, August 9, 2011

Doing things Asynchronously on Android

Did I mention I'm still learning Android? Here are some things I wrestled with getting started.

I had a background job I needed to run in this application, and I wanted to display progress as it worked.  I saw several possible solutions:
  1. An Activity with a Java Thread
  2. An Activity with an Android AsyncTask
  3. A Service with a Java Thread
  4. An Intent Service
I didn't know about Intent Services when I started, and because I needed to update the UI based on feedback from the worker thread, I started with AsyncTask.  I really struggled with using AsyncTask because it lacks good separation of concerns.  Your background code is stuck in the same class as your UI update code.  Not very nice.

I also wanted to have my background code in a class that had no Android framework dependencies.  Just a pojo.  That made it even more difficult.

The problem was resolved when I realized that the work I needed to do in the background was best thought of as a service.  AsyncTask seems to be really just for small, but long-running foreground tasks.  You use AsyncTask to keep from blocking the  main thread in those cases.

An AsyncTask class looks like this:

AsyncTask task = new AsyncTask() {
			@Override
			protected Object doInBackground(Object... arg0) {
				return null;
			}
			
			@Override
			protected void onCancelled() {
				super.onCancelled();
			}
			
			@Override
			protected void onPreExecute() {
				super.onPreExecute();
			}
			
			@Override
			protected void onPostExecute(Object result) {
				super.onPostExecute(result);
			}
			
			@Override
			protected void onProgressUpdate(Object... values) {
				super.onProgressUpdate(values);
			}
		};

The "onWhatever"  methods get called by the framework on the main UI thread, while the doInBackground runs in a separate worker thread when you start the task.

I then went down the plain android.app.Service path.  Extending service works fine, but you have to manage the service life cycle, and things like threading and re-entrance, yourself.

android.app.IntentService relieves you of that burden.  All you have to do is:

public class FooService extends IntentService {

	public FooService() {
		super("FooService");
	}

	public FooService(String name) {
		super(name);
	}

	@Override
	protected void onHandleIntent(Intent intent) {

	}
}

onHandleIntent will execute in a background thread.  To start the service (from an activity):

startService(new Intent(this, FooService.class));

Of course, the irony is that the UI is not currently getting updates from the service! It will in a future release, though. And I'm still extending a framework class. I'll be taking another this whole thing again soon.

No comments:

Post a Comment