Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design pattern for catching unhandled exceptions in AsyncTask

Folks,

I catch unhandled Android exceptions via a code snippet like this, at the top of onCreate:

    try {
        File crashLogDirectory = new File(Environment.getExternalStorageDirectory().getCanonicalPath() + Constants.CrashLogDirectory);
        crashLogDirectory.mkdirs();

        Thread.setDefaultUncaughtExceptionHandler(new RemoteUploadExceptionHandler(
                this, crashLogDirectory.getCanonicalPath()));
    } catch (Exception e) {
        if (MyActivity.WARN) Log.e(ScruffActivity.TAG, "Exception setting up exception handler! " + e.toString());
    }

I'd like to come up with something similar for about two dozen AsyncTasks I use in my android application, so unhandled exceptions that occur in doInBackground are caught & logged.

Problem is, because AsyncTask takes arbitrary type initializers, I am not sure how to declare a superclass, from which all my AsyncTasks inherit, that sets up this unhandled exception handler.

Can anyone recommend a good design pattern for handling unhandled exceptions in the doInBackground method of AsyncTask that does not involve copy-and-paste of code like that above for every new AsyncTask definition?

Thanks!

UPDATE

Here is the design pattern I used, after looking more closely at the source of AsyncTask

import java.io.File;

import android.content.Context;
import android.os.AsyncTask;
import android.os.Environment;
import android.util.Log;

public abstract class LoggingAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {

    protected void setupUnhandledExceptionLogging(Context context) {
        try {
            File crashLogDirectory = new File(Environment.getExternalStorageDirectory().getCanonicalPath() + Constants.CrashLogDirectory);
            crashLogDirectory.mkdirs();

            Thread.setDefaultUncaughtExceptionHandler(new RemoteUploadExceptionHandler(
                    context, crashLogDirectory.getCanonicalPath()));
        } catch (Exception e) {
            if (MyActivity.WARN) Log.e(ScruffActivity.TAG, "Exception setting up exception handler! " + e.toString());
        }

    }
}

Then I define my tasks as follows:

private class MyTask extends LoggingAsyncTask<Void, Void, HashMap<String, Object>> {
    protected HashMap<String, Object> doInBackground(Void... args) {
        this.setupUnhandledExceptionLogging(MyActivity.this.mContext);
        // do work
        return myHashMap;
  }
}

Obviously your task can take whatever params necessary with this pattern. It's up to you to define RemoteUploadExceptionHandler to do the necessary logging/uploading.

like image 595
esilver Avatar asked Aug 11 '11 05:08

esilver


1 Answers

I wouldn't go as far as to call it a design pattern, but just wrap doInBackground() and initialize and/or catch exceptions as necessary.

public abstract class AsyncTaskWrapper<Params, Progress, Result> extends
        AsyncTask<Params, Progress, Result> {

    protected Exception error;

    protected Result doInBackground(Params... params) {
        try {
            init();

            return doRealWork(params);
        } catch (Exception e) {
            error = e;

            Log.e("TAG", e.getMessage(), e);

            return null;
        }
    }

    protected abstract void init();

    protected abstract Result doRealWork(Params... params);
}
like image 121
Nikolay Elenkov Avatar answered Oct 30 '22 12:10

Nikolay Elenkov