On Android, an application must perform all non-UI computations on a background thread. In fact, the Android OS enforces this by displaying a “Application Not Responding” (ANR) dialog for applications that do too much on the UI thread, and are therefore not responsive to user actions.

A built-in way to push computations onto the background thread is to use an AsyncTask. Something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class LargeComputation extends AsyncTask<Params, Progress, Result> {
    protected void onPreExecute() {
    setupProgressDisplay();
    }
    protected Result doInBackground(final Params... params) {
        return largeComputationResult(params);
    }
    protected void onProgressUpdate(Progress... progress) {
    updateProgressDisplay(progress);
    }
    protected void onPostExecute(Result result) {
        computationIsComplete(result);
    }
}

You can invoke the computation via:

new LargeComputation().execute(instanceOfParams);

This looks simple enough when executed from the UI thread, but what if you’re executing this task from a background thread? You probably don’t want another thread in this case. Also, you might want to use this task from multiple places in your application, so the methods you want to invoke for onProgressUpdate or onPostExecute might need to be different.

To the rescue comes RxAndroid which uses an observer-observable pattern. I’ve added a listener notion as well to deal with different actions for different scenarios.

Here’s an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public void doLargeComputation(
     final IComputationListener listener,
     final OtherParams          params) {
     Subscription subscription = doLargeComputationCall(params)
         .subscribeOn(Schedulers.io())
         .observeOn(AndroidSchedulers.mainThread())
         .subscribe(new Observer<List<Result>>>() {
                 @Override public void onNext(final List<Result> results) {
                    listener.doLargeComputationComplete(results);
                }
                @Override public void onCompleted() {}
                @Override public void onError(final Throwable t) {
                    listener.doLargeComputationFailed(t);
                }
            }
        );
}
private Observable<List<Result>> doLargeComputationCall(
        final OtherParams params) {
    return Observable.defer(new Func0<Observable<List<Result>>>() {
            @Override public Observable<List<Result>> call() {
                     List<Result> results = doTheRealLargeComputation(params);
                if (results != null && 0 < results.size()) {
                    return Observable.just(results);
                }
                return Observable.error(new ComputationException("Could not do the large computation"));
            }
        }
    );
}

Looks like a lot of stuff, but let’s walk through it.

Line 1: This is the method you’ll call to do the large computation. By passing in a listener, you can receive callbacks from anywhere in your application.
Line 5: We’re creating the subscriber/observer of the large computation.
Line 6: We’ll execute on the background thread, if we’re not already there.
Line 7: We’ll observe on the main thread.
Line 8: Begins the definition of our observer. He’s watching for a List<Result> result.
Line 9: onNext is called when the a List result is available. The result is then passed on to the listener.
Line 13: onCompleted is called when the observable shuts down. If there’s only one result, you needn’t do anything here.
Line 15: onError is called when an error occurred in the large computation. The error is then passed on to the listener.
Line 22: Here’s our observable, where the large computation is done. Note the List result.
Line 25: Boilerplate for an observable, with your result type inserted.
Line 26: More boilerplate.
Line 28: Finally (whew!) the computation.
Line 31: Return an observable positive result.
Line 34: Return an observable error (negative result).

The IComputationListener looks like this:

1
2
3
4
5
6
7
public interface IComputationListener {
   public void doLargeComputationComplete(final List<Result> results);
   public void doLargeComputationFailed(final Throwable t);
}

You can implement this interface wherever you need to receive callbacks about success or failure.

In summary, I’ve used this pattern for all database queries (read and write) and all server API calls. It’s so simple, I can add new services, whether database or API, quickly.

For more information on RxAndroid see https://github.com/ReactiveX/RxAndroid.