Search code examples
javaandroidandroid-asynctaskextend

Want to create a generic AsyncTask - how?


In my Apps I usually have lots of AsyncTasks. They all look the same thus share the same design. So I would like to optimize this a little bit further and create a generic MyAsyncTask from which my AsyncTasks extend. But I don't know how to do that.

Here's one of my AsyncTasks. They all differ only on the methods/vars surrounded with *:

public class OneOfMyAsyncTasks extends AsyncTask<Void, Void, ***Cursor***> {

    private Context                      context;
    private MyProgressDialog             dialog;
    private OnAsyncTaskCompletedListener listener;
    private String                       search;
    private int                          task_id;

    public OneOfMyAsyncTasks(int task_id, Context context, OnAsyncTaskCompletedListener listener) {
        super();

        this.context = context;
        this.listener = listener;
        this.task_id = task_id;
    }


    public OneOfMyAsyncTasks(int task_id, Context context, OnAsyncTaskCompletedListener,
                        ***String search***) {
        super(task_id, context, listener);

        ***this.search = search;***
    }

    protected void attach(Context context, OnAsyncTaskCompletedListener listener) {
        this.context = context;
        this.listener = listener;

        processCreateDialog();
    }

    protected void detach() {
        processDismissDialog();

        if (context != null) {
            context = null;
        }

        if (listener != null) {
            listener = null;
        }
    }

    @Override
    protected ***Cursor*** doInBackground(Void... voids) {
        ***return MyApplication.getSqliteOpenHelper().fetchSomething(search);***
    }

    @Override
    protected void onPostExecute(***Cursor cursor***) {
        if (listener != null) {
            listener.onAsyncTaskCompleted(task_id, ***cursor***);
        }

        detach();
    }

    @Override
    protected void onPreExecute() {
        processCreateDialog();
    }

    private void processCreateDialog() {
        if (context != null) { 
            dialog = MyProgressDialog.show(context, null, null, true, false);
        }
    }

    private void processDismissDialog() {
        if (dialog != null) {
            try {
                dialog.dismiss();
            } catch (Exception exception) {
            }

            dialog = null;
        }
    }
}

My idea is to create a MyAsyncTask that does contain all shown above with the exception of:

  • The method doInBackground
  • The method onPostExecute
  • The second constructor
  • ... and the signature of the AsyncTask itself (the third parameter)

These must be set from the specific AsyncTasks that do extend from this generic MyAsyncTask.

Any help is highly appreciated.

EDIT: Here's what I did so far - without success. The extending class throws two errors that are written in the code below. First the Abstract Class:

public abstract class MyAsyncTask<A, B, C> extends AsyncTask<A, B, C> {

        protected Context                      context;
        protected MyProgressDialog             dialog;
        protected OnAsyncTaskCompletedListener listener;
        protected int                          task_id;

        public MyAsyncTask(int task_id, Context context, OnAsyncTaskCompletedListener listener) {
            super();

            this.context = context;
            this.listener = listener;
            this.task_id = task_id;
        }

        protected void attach(Context context, OnAsyncTaskCompletedListener listener) {
            this.context = context;
            this.listener = listener;

            processCreateDialog();
        }

        protected void detach() {
            processDismissDialog();

            if (context != null) {
                context = null;
            }

            if (listener != null) {
                listener = null;
            }
        }

        @Override
        protected void onPostExecute(C result) {
            if (listener != null) {
                listener.onAsyncTaskCompleted(task_id, result);
            }

            detach();
        }

        @Override
        protected void onPreExecute() {
            processCreateDialog();
        }

        private void processCreateDialog() {
            if (context != null) {
                dialog = MyProgressDialog.show(context, null, null, true, false);
            }
        }

        private void processDismissDialog() {
            if (dialog != null) {
                try {
                    dialog.dismiss();
                } catch (Exception exception) {
                }

                dialog = null;
            }
        }
    }

And here's the idea of a class extending that Abstract class. The two errors are written within the code:

public class MyAsyncTaskImpl extends MyAsyncTask<Void, Void, Cursor> {
    // --> Error: MyAsyncTask cannot be resolved to a type - Create class 'MyAsyncTask<T1, T2, T3>'

    private String search;

    public MyAsyncTaskImpl(int task_id, Context context, OnAsyncTaskCompletedListener listener, String search) {
        super(task_id, context, listener);

        this.search = search;
    }

    @Override
    protected Cursor doInBackground(Void... voids) {
        // --> Error: The method doInBackground(Void...) of type MyAsyncTaskImpl must override or implement a supertype method - Remove '@Override' annotation        

        return MyApplication.getSqliteOpenHelper().fetchSomething(search);
    }
}

Solution

  • You can create an abstract base class with two generic type arguments - R - for result type and T for the search argument.

    public abstract class MyAsyncTask<R, T> extends AsyncTask<Void, Void, R> {
        private Context context;
        private MyProgressDialog dialog;
        private OnAsyncTaskCompletedListener listener;
        private T search;
        private int task_id;
    
        public MyAsyncTask(int task_id, Context context,
                OnAsyncTaskCompletedListener listener) {
            super();
    
            this.context = context;
            this.listener = listener;
            this.task_id = task_id;
        }
    
        public MyAsyncTask(int task_id, Context context,
                OnAsyncTaskCompletedListener listener, T search) {
            this(task_id, context, listener);
    
            this.search = search;
        }
    
        protected void attach(Context context, OnAsyncTaskCompletedListener listener) {
            this.context = context;
            this.listener = listener;
    
            processCreateDialog();
        }
    
        protected void detach() {
            processDismissDialog();
    
            if (context != null) {
                context = null;
            }
    
            if (listener != null) {
                listener = null;
            }
        }
    
        @Override
        protected void onPostExecute(R result) {
            if (listener != null) {
                listener.onAsyncTaskCompleted(task_id, result);
            }
    
            detach();
        }
    
        @Override
        protected void onPreExecute() {
            processCreateDialog();
        }
    
        private void processCreateDialog() {
            if (context != null) {
                dialog = MyProgressDialog.show(context, null, null, true, false);
            }
        }
    
        private void processDismissDialog() {
            if (dialog != null) {
                try {
                    dialog.dismiss();
                } catch (Exception exception) {
                }
    
                dialog = null;
            }
        }
    } 
    

    Then you can extend this class with specific implementations as follows:

    public class MyAsyncTaskimpl extends MyAsyncTask<Cursor, String> {
    
        public MyAsyncTaskimpl(int task_id, Context context,
                OnAsyncTaskCompletedListener listener, String search) {
            super(task_id, context, listener, search);
            // TODO Auto-generated constructor stub
        }
    
        @Override
        protected Cursor doInBackground(Void... params) {
            // TODO Auto-generated method stub
            return null;
        }
    
    }