Error handling in AsyncTasks

A quick trick to process errors in AsyncTasks. Let’s say you have an AsyncTask that computes a result of type MyType. To handle exceptions, you can define it like this instead:

class MyAsyncTask extends AsyncTask<Void, Void, Object> {
    protected Object doInBackground(Void... params) {
        try {
            // ... do something ...
            return result;
        } catch (Exception exception) {
            return exception;
        }
    }

    protected void onPostExecute(Object object) {
        if (object instanceof MyType) {
            MyType result = (MyType) result;
            // ... process result ...
        } else if (result instanceof Exception) {
            Exception exception = (Exception) result;
            // ... process error ...
        } else {
            throw new RuntimeException("This shouldn't have happened! Result was " + result);
        }
    }
}

The solution can be further improved by introducing intermediate type like this:

class ValueOrError<T> {
    public T value;
    public Exception exception;
}

This would give you a more descriptive signature AsyncTask<Void, Void, ValueOrError<T>>, but if I went that way, I’d rather declare a special AbstractErrorHandlingAsyncTask subclass:

public abstract class AbstractErrorHandlingAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Object> {
    protected final Object doInBackground(Params... params) {
        try {
            return computeResult(params);
        } catch (Exception exception) {
            return exception;
        }
    }

    protected abstract Result computeResult(Params... params) throws Exception;

    protected final void onPostExecute(Object object) {
        if (object instanceof Exception) {
            onError((Exception) object);
        } else {
            onResult((Result) object);
        }
    }

    protected abstract void onResult(Result object);

    protected abstract void onError(Exception object);
}

Single updateUI method

This is a pattern that will simplify your UI code (at the slight expense of performance, maybe).

Let’s say you have an activity that allows you to:

  1. select an item from list,
  2. then display a list of sub-items, and
  3. then select one of them for viewing in another activity
  4. or reset your choice.

Maybe, your code for that activity would look like this:

private ItemObject selectedItem = null;

private TextView titleView;
private TextView descriptionView;
private ListView titleView;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.my_layout);

    titleView = ((TextView) findViewById(R.id.title));
    descriptionView = ((TextView) findViewById(R.id.description));
    listView = ((ListView) findViewById(R.id.list));

    listView.setAdapter(new TopLevelAdapter());

    // Hook up event listeners
}

public void onResetButtonClick(View resetButton) {
    titleView.setText("Nothing selected");
    descriptionView.setVisibility(View.GONE);
    listView.setAdapter(new TopLevelAdapter());
    selectedItem = null;
}

public void onItemClick(AdapterView adapterView, View view, int position, long id) {
    selectedItem = (ItemObject) adapterView.getItemAtPosition(position);
    titleView.setText(selectedItem.title);
    descriptionView.setVisibility(View.VISIBLE);
    descriptionView.setText(selectedItem.description);
    listView.setAdapter(new SubAdapter(selectedItem ));
}

public void onSelectButtonClick(View selectButton) {
    // ... start activity for viewing selectedItem
}

This code looks pretty logical – when we have an event, we react on it by making necessary changes to UI and the selectedItem field.

Unfortunately, there is a couple of problems.

  1. Here we have only two event handlers. What if we have ten? Every change to UI structure or behavior will result in reviewing all of them just to be sure that nothing is broken.
  2. Again, we have only three views here. If there were more, it would be really hard to keep track of what views need to be hidden/shown in each handler. On the other hand, updating visibility of ALL of them will bloat the code.
  3. To fully understand how UI changes, you’ll need to read all of the event handler methods. It’s not obvious what states activity UI may have and what are transitions between them.

So, this is the solution: make a single method that will update ALL of your UI based on activity state. For our example:

public void updateUI() {
    if (selectedItem != null) {
        titleView.setText(selectedItem.title);
        descriptionView.setVisibility(View.VISIBLE);
        descriptionView.setText(selectedItem.description);
        listView.setAdapter(new SubAdapter(selectedItem ));
    } else {
        titleView.setText("Nothing selected");
        descriptionView.setVisibility(View.GONE);
        descriptionView.setText(selectedItem.description);
        listView.setAdapter(new TopLevelAdapter());
    }
}

Then the activity code would be much simpler:

private ItemObject selectedItem = null;

private TextView titleView;
private TextView descriptionView;
private ListView titleView;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.my_layout);

    titleView = ((TextView) findViewById(R.id.title));
    descriptionView = ((TextView) findViewById(R.id.description));
    listView = ((ListView) findViewById(R.id.list));

    updateUI();

    // Hook up event listeners
}

public void onResetButtonClick(View resetButton) {
    selectedItem = null;
    updateUI();
}

public void onItemClick(AdapterView adapterView, View view, int position, long id) {
    selectedItem = (ItemObject) adapterView.getItemAtPosition(position);
    updateUI();
}

public void updateUI() {
    // see code above
}

As you can see, now we:

  1. have a single place of reference of how activity should look like for different states.
  2. Have greatly simplified event handlers: all they need to do now is to change state and ask for a UI update.
  3. This enforces clean separation between internal state (selected item) and UI state (texts, visibilities, etc).
  4. It even lays base for the separation of UI, event handling and internal state into view, controller and model of an MVC pattern!

If the updateUI method becomes too large, you can always split it into several based on different states. In our example, you may split it into updateUISelectTopLevelItem and updateUISelectSubItem and call them for respective cases:

public void updateUI() {
    if (selectedItem != null) {
        updateUISelectSubItem();
    } else {
        updateUISelectTopLevelItem();
    }
}

The other problem that may arise is when you actually need to know if some part of state has changed. E.g., you do not want to re-set list view’s adapter if the selected item didn’t change. The one way to deal with this is to hold an extra field oldSelectedItem. It would be view-specific, and if the view layer is separated into its own class, this would be a private field of that class. It is not a part of Activity state, in other words – it belongs only to views.

Then, in the updateUI method we can compare selectedItem and oldSelectedItem to see if there’s a need to update the adapter (or anything else) and then do oldSelectedItem = selectedItem.

Painless Cursors

I (partly) borrowed this idea from Android’s MediaStore. When you define a DatabaseHelper class to abstract out data operations, usually it is more convernient to return a Cursor with data instead of a List of DTOs. Android framework is designed for efficiency, and transforming cursor data into objects just to disassemble them into properties in some ArrayAdapter isn’t helping to conserve memory and CPU.

But when a Cursor is passed to you from some method – even if you wrote that one – you usually have no idea what values of that cursor’s columns are. One of the ways is to use meaningful aliases in your SQL query. Then you can get values from cursor like this:

cursor.getInt(cursor.getColumnIndex("number_of_hits"))

Unfortunately, this also isn’t as cheap as it could be, because it involves HashMap creation (once) and lookup with some boxing/unboxing on every call (see source).

So, long story short, this is how I’m defining cursors now:

public interface Cursors {
    public interface Customers {
        String[] COLUMNS = { "_id", "first_name", "last_name"  };
        int FIRST_NAME = 1;
        int LAST_NAME = 2;
    }

    public interface Orders {
        String QUERY = "SELECT o._id, o.date_created, " +
                "(SELECT SUM(i.cost) FROM order_item i WHERE i.order_id = o.id), " +
                "(SELECT COUNT(*) FROM order_item i WHERE i.order_id = o.id) " +
                "FROM order WHERE o._id = ?";

        int ID = 0;
        int DATE_CREATED = 1;
        int TOTAL = 2;
        int N_ITEMS = 3;
    }
}

This way I have all information about cursor grouped in one place. With this approach, query methods in database helper class look like this:

public Cursor getCustomersCursor() {
    return getReadableDatabase().query("customer", Cursors.Customers.COLUMNS, null, null, null, null, null);
}


public Cursor getOrdersCursor(final String orderId) {
    return getReadableDatabase().rawQuery(Cursors.Orders.QUERY, new String[] { orderId });
}

And then I can use these cursors like this:

public void bindView(View view, Context context, Cursor cursor) {
    // ...
    orderIdView.setText(cursor.getString(DatabaseHelper.Cursors.Orders.ID));
    orderDateView.setText(cursor.getString(DatabaseHelper.Cursors.Orders.DATE_CREATED));
    orderTotal.setText(cursor.getString(DatabaseHelper.Cursors.Orders.TOTAL));
    orderCount.setText(cursor.getString(DatabaseHelper.Cursors.Orders.N_ITEMS));
}

This way you can have it all:

  1. fast access to cursor data through column indices,
  2. readable and refactor-friendly (!) declaration of what you access,
  3. grouping of all information about a cursor in one place, easy to find, change and refactor.

Also, similar approach can be applied to tables:

public interface Tables {
    public interface Customer {
        String TABLE = "customer";
        String CREATE = "CREATE TABLE customer(_id, first_name, last_name, PRIMARY KEY(_id))";

        String ID = "_id";
        String FIRST_NAME = "first_name";
        String LAST_NAME = "last_name";
    }
}

Activity Aspects

Sometimes you have a lot of activities in your app, each having something in common with others. The usual way to avoid code duplication in this case is to have something like an AbstractActvity superclass (or a hierarchy of superclasses), abstracting out commonalities.

Unfortunately, there are cases when this appreoach does not work. Consider this:

  1. some activities need to be able to display progress dialog while doing an API request
  2. some activities need to require user to sign in before letting him do anything else
  3. some activities need to display an error dialog of the same type
  4. some activities need to have title that is passed in an Intent’s extra

So what would you do if activity A needed 1 and 2, activity B needed 2 and 3, activity C needed 3 and 4, etc? Since Java has no multiple inheritance, code duplication seems unavoidable.

Yet, there is a way to extract commonalities not via inheritance, but via composition.

What if each of these 1-4 commonalities was fully described by a separate class (I call it an “aspect”), encapsulating required behavior? Then, all that activities would need to do is to just hook up the aspects it needs in onCreate (and other callback methods), without a need to extend a superclass.

For example, ProgressDialogAspect may look like this:

public class ProgressDialogAspect {
        private final Activity activity;
        private final int dialogId;

        public ProgressDialogAspect(final Activity activity, final int dialogId) {
            this.activity = activity;
            this.dialogId = dialogId;
        }

        public ProgressDialog createDialog() {
            final ProgressDialog dialog = new ProgressDialog(this.activity);
            dialog.setMessage(this.activity.getString(R.string.please_wait));
            return dialog;
        }

        public void showProgress() {
            this.activity.showDialog(this.dialogId);
        }

        public void hideProgress() {
            this.activity.dismissDialog(this.dialogId);
        }
    }

Then, hooking it up in an Activity will look like this:

private static final int DIALOG_PROGRESS = 0;
    private ProgressDialogAspect progressDialogAspect;

    // ...

    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.progressDialogAspect = new ProgressDialogAspect(this, DIALOG_PROGRESS);
        // ...
    }

    @Override
    protected Dialog onCreateDialog(final int id) {
        switch (id) {
            case DIALOG_PROGRESS: {
                return this.progressDialogAspect.createDialog();
            }
            // ...
        }
    }

    public void onSomething(View button) {
        this.progressDialogAspect.showProgress();
    }

Another example: an aspect requiring user to log in before using an Activity:

public class RequireLoginAspect {
        private final Activity activity;
        private final int requestCode;

        public RequireLoginAspect(final Activity activity, final int requestCode) {
            this.activity = activity;
            this.requestCode = requestCode;
        }

        public boolean checkLogin() {
            final String token = Preferences.get(this.activity).getString(Preferences.AUTH_TOKEN, null);

            if (token == null) {
                this.activity.startActivityForResult(new Intent(this.activity, LoginActivity.class), this.requestCode);
                return false;
            }

            return true;
        }

        public void processLoginActivityResultCode(final int resultCode) {
            switch (resultCode) {
                case Activity.RESULT_OK: {
                    break;
                }
                case Activity.RESULT_CANCELED: {
                    this.activity.finish();
                    break;
                }
            }
        }
    }

This aspect could be hooked up in this way:

private static final int REQUEST_CODE_LOGIN = 0;
    private RequireLoginAspect requireLoginAspect;

    // ...

    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.requireLoginAspect = new RequireLoginAspect(this, REQUEST_CODE_LOGIN);
        // ...
    }

    protected void onResume() {
        super.onResume();
        if (!this.requireLoginAspect.checkLogin()) {
            return;
        }
        // ...
    }

    protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
        switch (requestCode) {
            case REQUEST_CODE_LOGIN: {
                this.requireLoginAspect.processLoginActivityResultCode(resultCode);
                return;
            }
            // ...
        }
    }

Also, note that aspects do not have their own dialog and request codes – this lets us to not worry about clashes between aspect’s and Activity’s codes . Also, aspects written in this way may be re-used in other apps with no code change (though for complete re-usability resource IDs need to be passed into aspect as well as request/dialog codes).

Hope this helps.