Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

After ASyncTask.execute() do x() from Activity

This is one I'm not sure how to go about. Basically I have an ASyncTask class thats doing its business as usual in the background. I'd like to do something after its finished. Now before you jump ahead and say "just use onPostExecute()", theres a catch. The method I need run is in the activity and not the Task class.

The way I see it, I have 2 options.

A:

    CustomTask task = new CustomTask();
    task.execute(passedParams);
            //when(task.execute is finished)
            {
                doX();
            }

I hope I can do it this way as Its so simple and lets me check when the task is completed without having to constantly poll it for activity and getStatus() on the activity. I don't think I'll get this lucky but If anyone has a way of doing it, that'd be great

B:

Pass the activity as a paramater to the ASyncTask. This is messy and I'm not happy about using it but asides from that and the object reference, I don't know if it will work

    CustomTask task = new CustomTask();
    task.execute(passedParams,MyActivity);

Then in the Tasks onPostExecute, I can just have it call the MyActivity.doX();


C:

A third way would be to make the asynctask a private class in the activity itself but i really would like to keep it separate. Resusability and what not –

Any thoughts on this?

To summarize, Need to doX() after task.execute is finished. Any ideas appreciated.


D:

Ok I know I'm on a roll here. I keep thinking up new solutions. A class method or static method that can be called from any where.

public class ProfileSettings extends Activity
{
      public static void doX()
      {
          //Logic...
      }
}

From AsyncTask

MyActivity.doX();
like image 444
OVERTONE Avatar asked Dec 27 '22 02:12

OVERTONE


2 Answers

Option B should work and is sometimes a good option, but sometimes I use anonymous classes for this. When you call it from your activity:

CustomTask task = new CustomTask() {
    @Override
    protected void onPostExecute(Long result) {
        super.onPostExecute(result);
        MyActivity.this.doX();
    }
}.execute();
like image 76
kabuko Avatar answered Jan 08 '23 20:01

kabuko


Option A:

Android API has already provided built-in function for this purpose AsyncTask.get():

CustomTask task = new CustomTask();
task.execute(passedParams);
Result result = task.get(); // <- Block UI thread and waiting for AsyncTask finish.
this.doX(result);

As you can see, this is a bad practice as it blocks UI thread and may cause ANR exception, By doing this, you are actually sacrifice the benefit of AsyncTask, and make it running synchronously with UI thread.


Option B and C:

Both are correct way of doing things, by calling doX() method in onPostExecute() method,

AsyncTask, as its name stated, run a background thread asynchronously with UI thread, and once the background thread is finished, onPostExecute method is called on UI thread. There is no way to tell exactly when onPostExecute method is called (i.e. when doInBackground method is finished) at project build time, as it is determined at app run time, the only thing we know is onPostExecute method is guaranteed to be called on UI thread at some point in the future, In another word, when writing code at project build time, we never know exactly when the doInBackground is finished and code execution jump back to UI thread outside onPostExecute method (Unless you implement some waiting mechanism in code like Option A). So the purpose of onPostExecute method is for processing everything after doInBackground method is finish, this is also why the only argument of onPostExecute method is the result returned from doInBackground method.

The difference between Option B and C is whether to implement AsyncTask as inner class or separate class. This has been aksed and discussed many times in StackOverflow. Most people think it is good to separate them for resusability reason or etc. From my point of view, I don't agree with it. Java Programming Language has its reason provide inner class syntax to suit some special coding situations, when talking about code refactoring from a OOP perspective, think more from problem abstraction level, not simply strip inner class out from Activity class at code level. As you can see in your example, by isolating AsyncTask from Activity, you don't gain any real benefit but rather increase the code complexity (need pass activity context reference between classes) to solve problem.

I think you real question is whether or not we should isolate AsyncTask inner class implementation from Activity. For a better OOP code refactoring (reusability, testability and etc.), checkout my answer in this StackOverflow question to see how to isolate business layer from application UI layer properly.

like image 45
yorkw Avatar answered Jan 08 '23 21:01

yorkw