DRY: a case with AsyncTasks

android, android-asynctask, dry, java

Solution

You can create classes that contain most of your boilerplate code. E.g.

public class SpecialAsyncTask<T> extends AsyncTask<String, Void, T> {

    public interface ResultProvider<T> {
        T generateResultInBackground(String... params);
    }

    public interface ResultConsumer<T> {
        void handleResultInForeground(T result);
    }

    private final ResultProvider<T> mProvider;
    private final ResultConsumer<T> mConsumer;
    private SpecialAsyncTask(ResultProvider<T> provider, ResultConsumer<T> consumer) {
        mProvider = provider;
        mConsumer = consumer;
    }

    @Override
    protected T doInBackground(String... params) {
        return mProvider.generateResultInBackground(params);
    }

    @Override
    protected void onPostExecute(T result) {
        mConsumer.handleResultInForeground(result);
    }

    public static <T> void execute(ResultProvider<T> provider, ResultConsumer<T> consumer, String... params) {
        new SpecialAsyncTask<T>(provider, consumer).execute(params);
    }
}

is an example how you could keep `Object1` as a generic parameter while being able to specify an object that only needs to implement an interface to handle code that would otherwise have to be inside a new `AsyncTask` instance.

With a schema like that you could for example define some common code as static content:

class Providers {
    public static final ResultProvider<String> HTTP_GETTER = new ResultProvider<String>() {

        @Override
        public String generateResultInBackground(String... params) {
            return MagicHttpLibrary.getContentAsString(params[0]);
        }

    };
}

And you can just use `Providers.HTTP_GETTER` as parameter instead of implementing `doInBackground`. Or create a new class hierarchy of that implement one of those interfaces with different methods to access them (like factories for example)

Use of above example would look for example like below

class User extends Activity implements ResultConsumer<String> {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        SpecialAsyncTask.execute(Providers.HTTP_GETTER, this , "http://google.com");
        SpecialAsyncTask.execute(Providers.HTTP_GETTER, this , "http://yahoo.com");
    }

    @Override
    public void handleResultInForeground(String result) {
        Toast.makeText(this, result, Toast.LENGTH_LONG).show();
    }
}

and there is more or less no repeated code besides the different method calls. It depends on how you want to use a class and what actually changes in the code to know how to design something like that. Identify the parts that need to be parametrized and move code that repeats into a re-used place (inheritance / composition).

Problem

I'm developing an Android app which has a lot of different requests for web services. Every request is done in a subclass of `AsyncTask` in this manner: ``` (new AsyncTask<String, Void, Object1>() { @Override protected Object1 doInBackground(String... params) { // network request and parsing to Object1 Object1 obj = new Object1(); obj1 = Parser.parseObject1(httpClient.execute(...)); return obj1; } @Override protected Object1 onPostExecute(Object1... ret) { return ret[0]; } }).execute(); ``` `Object1` is a placeholder for different objects (`Car`, `Bicycle`, `Truck`...), each one in a different `AsyncTask`. What are my alternatives other than returning the output of httpClient in a `String` and parsing in the Main Thread (UI Thread)? Avoid parsing in the UI Thread sounds reasonable if it's going to parse a lot of data, am I right? -= UPDATE =- Let me rephrase the question: I'm asking for a more intelligent way to develop my application avoiding being repetitive (`AsyncTask` has a lot of boilerplate code). The way I did was by creating 20+ subclasses of `AsyncTask`, which clearly is not DRY (do not repeat yourself). In iOS we have lambda expressions so callbacks done in web requests are very easy and succinct.

Original source