Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practice to launch AsyncTask from custom view

It is quite common to spawn a time consuming computation thread. Later, we require to update Activity or Fragment with computation result.

All the while, I'm following the below guidelines. It works well for me till now.

AsyncTask needs to onPostExecute UI Fragment

  1. Use setRetainInstance(true) UI-less fragment.
  2. Use setTargetFragment and getTargetFragment technique
  3. Please refer to https://stackoverflow.com/a/12303649/72437

AsyncTask needs to onPostExecute UI Activity

  1. Use setRetainInstance(true) UI-less fragment.
  2. Use onAttach and onDetach to store reference to Activity. Google seems doesn't encourage using getActivity. http://developer.android.com/guide/components/fragments.html
  3. Please refer to https://stackoverflow.com/a/16305029/72437

However, how about case for a class derived from View? I plan to launch AsyncTask from the custom View. However, how can I onPostExecute back to the View?

The reason I'm asking so is, in my custom view, certain touch event will trigger it to redraw itself with a new bitmap. Generating the new bitmap is time consuming. Hence, I plan to launch a AsyncTask, to generate such bitmap, and pass back to custom View. However, configuration change might cause custom View to be recreated. Hence, I need to ensure my AsyncTask can have correct View reference during onPostExecute.

like image 630
Cheok Yan Cheng Avatar asked Nov 13 '14 16:11

Cheok Yan Cheng


People also ask

When to use AsyncTask Android?

Generally it is convenient to use AsyncTask when you must "skip back" to UI thread when the background task is done or when you have to give some feedback to UI thread during task execution. Otherwise it's just overhead. You are not forced to use AsyncTask.

Is it possible to start AsyncTask from background thread?

Android App Development for Beginners Android AsyncTask going to do background operation on background thread and update on main thread. In android we cant directly touch background thread to main thread in android development. asynctask help us to make communication between background thread to main thread.

How to implement AsyncTask in Android?

To start an AsyncTask the following snippet must be present in the MainActivity class : MyTask myTask = new MyTask(); myTask. execute(); In the above snippet we've used a sample classname that extends AsyncTask and execute method is used to start the background thread.

How to call AsyncTask class in Android?

execute(); ... public class asyncextends AsyncTask<Void, Void, String> { protected String doInBackground(Void... progress) { ... } protected void onPreExecute() { ... } protected void onPostExecute(String result) { ... } } }


1 Answers

Assuming that you're using AsyncTask only for drawing-related operations (otherwise you should really revisit your logic - as comments suggest), you can create AsyncTask directly in your custom View class:

class MyView extends View {

    private MyAsyncTask currentTask = null;

    // View details

    @Override
    public void onAttachedToWindow() {
        currentTask = new MyAsyncTask(this);
        currentTask.execute();
    }

    @Override
    public void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (currentTask != null) {
            currentTask.cancel(true);
            currentTask = null;
        }
    }

    static class MyAsyncTask extends AsyncTask<Void, Void, Bitmap> {

        private WeakReference<MyView> viewRef;

        MyAsyncTask(MyView view) {
            viewRef = new WeakReference<>(view);
        }

        // background task implementation

        @Override
        public void onPostExecute(Bitmap bitmap) {
            MyView view = viewRef.get();
            if (view == null) {
                return;
            }

            // you now can safely update your view - we're on UI thread
        }

    }

}

That's how safe implementation would look like. It has some disadvantages and important parts:

  • At no point your AsyncTask should hold strong reference to View (that's why class is declared as static and holds WeakReference to View)
  • When you're not interested in result from AsyncTask anymore - cancel it
  • This implementation will just throw away possibly useful result from cancelled AsyncTask. If that's the issue - I would suggest to remove AsyncTask from View completely and search for others solutions (separate Executor or HandlerThread).

Also onPostExecute of AsyncTask will be called from the same looper thread which launched it (in your case that's main thread, so it does not matter if you start it from Activity or View, or wherever else, it all depends on how hard it would be to manage those tasks).

like image 177
Dmitry Zaytsev Avatar answered Sep 25 '22 13:09

Dmitry Zaytsev