379

I have this two classes. My main Activity and the one that extends the AsyncTask, Now in my main Activity I need to get the result from the OnPostExecute() in the AsyncTask. How can I pass or get the result to my main Activity?

Here is the sample codes.

My main Activity.

public class MainActivity extends Activity{

    AasyncTask asyncTask = new AasyncTask();

    @Override
    public void onCreate(Bundle aBundle) {
        super.onCreate(aBundle);            

        //Calling the AsyncTask class to start to execute.  
        asyncTask.execute(a.targetServer); 

        //Creating a TextView.
        TextView displayUI = asyncTask.dataDisplay;
        displayUI = new TextView(this);
        this.setContentView(tTextView); 
    }

}

This is the AsyncTask class

public class AasyncTask extends AsyncTask<String, Void, String> {

TextView dataDisplay; //store the data  
String soapAction = "http://sample.com"; //SOAPAction header line. 
String targetServer = "https://sampletargeturl.com"; //Target Server.

//SOAP Request.
String soapRequest = "<sample XML request>";    



@Override
protected String doInBackground(String... string) {

String responseStorage = null; //storage of the response

try {


    //Uses URL and HttpURLConnection for server connection. 
    URL targetURL = new URL(targetServer);
    HttpURLConnection httpCon = (HttpURLConnection) targetURL.openConnection();
    httpCon.setDoOutput(true);
    httpCon.setDoInput(true);
    httpCon.setUseCaches(false); 
    httpCon.setChunkedStreamingMode(0);

    //properties of SOAPAction header
    httpCon.addRequestProperty("SOAPAction", soapAction);
    httpCon.addRequestProperty("Content-Type", "text/xml; charset=utf-8"); 
    httpCon.addRequestProperty("Content-Length", "" + soapRequest.length());
    httpCon.setRequestMethod(HttpPost.METHOD_NAME);


    //sending request to the server.
    OutputStream outputStream = httpCon.getOutputStream(); 
    Writer writer = new OutputStreamWriter(outputStream);
    writer.write(soapRequest);
    writer.flush();
    writer.close();


    //getting the response from the server
    InputStream inputStream = httpCon.getInputStream(); 
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
    ByteArrayBuffer byteArrayBuffer = new ByteArrayBuffer(50);

    int intResponse = httpCon.getResponseCode();

    while ((intResponse = bufferedReader.read()) != -1) {
        byteArrayBuffer.append(intResponse);
    }

    responseStorage = new String(byteArrayBuffer.toByteArray()); 

    } catch (Exception aException) {
    responseStorage = aException.getMessage(); 
    }
    return responseStorage;
}

protected void onPostExecute(String result) {

    aTextView.setText(result);

}       

}   
God
  • 1,238
  • 2
  • 18
  • 45
Stella
  • 3,923
  • 4
  • 15
  • 15
  • You can create an interface like HelmiB explained or you can create a local broadcast receiver You can see the sample broadcast reciver implementation here http://wiki.workassis.com/android-local-broadcast-receiver/ – Bikesh M Jul 13 '16 at 13:00
  • Why don't use Observer pattern? – tur1ng Mar 17 '17 at 09:27

17 Answers17

779

Easy:

  1. Create interface class, where String output is optional, or can be whatever variables you want to return.

     public interface AsyncResponse {
         void processFinish(String output);
     }
    
  2. Go to your AsyncTask class, and declare interface AsyncResponse as a field :

     public class MyAsyncTask extends AsyncTask<Void, Void, String> {
       public AsyncResponse delegate = null;
    
         @Override
         protected void onPostExecute(String result) {
           delegate.processFinish(result);
         }
      }
    
  3. In your main Activity you need to implements interface AsyncResponse.

     public class MainActivity implements AsyncResponse{
       MyAsyncTask asyncTask =new MyAsyncTask();
    
       @Override
       public void onCreate(Bundle savedInstanceState) {
    
          //this to set delegate/listener back to this class
          asyncTask.delegate = this;
    
          //execute the async task 
          asyncTask.execute();
       }
    
       //this override the implemented method from asyncTask
       @Override
       void processFinish(String output){
          //Here you will receive the result fired from async class 
          //of onPostExecute(result) method.
        }
      }
    

UPDATE

I didn't know this is such a favourite to many of you. So here's the simple and convenience way to use interface.

still using same interface. FYI, you may combine this into AsyncTask class.

in AsyncTask class :

public class MyAsyncTask extends AsyncTask<Void, Void, String> {

  // you may separate this or combined to caller class.
  public interface AsyncResponse {
        void processFinish(String output);
  }

  public AsyncResponse delegate = null;

    public MyAsyncTask(AsyncResponse delegate){
        this.delegate = delegate;
    }

    @Override
    protected void onPostExecute(String result) {
      delegate.processFinish(result);
    }
}

do this in your Activity class

public class MainActivity extends Activity {
  
   MyAsyncTask asyncTask = new MyAsyncTask(new AsyncResponse(){
    
     @Override
     void processFinish(String output){
     //Here you will receive the result fired from async class 
     //of onPostExecute(result) method.
     }
  }).execute();

 }

Or, implementing the interface on the Activity again

public class MainActivity extends Activity 
    implements AsyncResponse{
      
    @Override
    public void onCreate(Bundle savedInstanceState) {

        //execute the async task 
        new MyAsyncTask(this).execute();
    }
      
    //this override the implemented method from AsyncResponse
    @Override
    void processFinish(String output){
        //Here you will receive the result fired from async class 
        //of onPostExecute(result) method.
    }
}

As you can see 2 solutions above, the first and third one, it needs to create method processFinish, the other one, the method is inside the caller parameter. The third is more neat because there is no nested anonymous class.

Tip: Change String output, String response, and String result to different matching types in order to get different objects.

SilentCloud
  • 1,677
  • 3
  • 9
  • 28
HelmiB
  • 12,303
  • 5
  • 41
  • 68
  • 20
    Totally wrote all of that up and then saw your answer :) Here's to thinking alike! +1. Also this way multiple things can listen to the results of the AsyncTask! – Roloc Sep 25 '12 at 02:24
  • Yes that's true, that's the function of `interface`. i forgot to set delegate though :). have added in `onCreate`. – HelmiB Sep 25 '12 at 02:40
  • this definitely work. try to post some of work you have done so far, especially the `AsyncTask` class – HelmiB Sep 27 '12 at 00:51
  • Hi. thank you for your reply, I edited my question and included the sample code. It's the original code I have. How can I put the interface with that? and I think I'm not getting the variables in a right way from the Aasynctask. – Stella Sep 27 '12 at 09:34
  • it's your `AsyncTask ` class. in this case your `AasyncTask`. i edited my answer based on your class you posted. – HelmiB Sep 27 '12 at 11:48
  • 8
    I am getting nullpointer exception because delegate is set to null, please clearify it – Reyjohn Sep 13 '13 at 21:20
  • 2
    Just a note for .net developers, one can use AutoResetEvents to achieve this and there is also a java implementation for autoresetevents but this is much cleaner. By the way, is ProcessFinish thread safe? – Syler Nov 29 '13 at 23:35
  • i would like to call doinbackground method in main activity, how can i achieve that? – AndroidOptimist Dec 17 '13 at 09:21
  • With this solution, I get an empty blank page before my next activity opens direclyt after. – Johan Jan 30 '14 at 08:17
  • I'm also getting a NullPointerException on the line: delegate.processFinish(s); by the way, I'm using a fragment that is implementing the AsyncResponse – user1064249 May 29 '14 at 15:25
  • I want to use the same Interface for a number of AsyncTask. Hence I modified the Interface as follows : public interface IntrfcResponseManager { void processResponse(String source,boolean output); } For this I cannot use asyncTask.delegate = this; in my MainActivity. How to do in this case ? – Syamantak Basu Jul 09 '14 at 11:37
  • 13
    for all those who are getting null pointer pass your interface to your asyncTask class constructor then assign it to a variable and then call processfinish() on that variable. For reference see accepted asnwer. http://stackoverflow.com/questions/9963691/android-asynctask-sending-callbacks-to-ui – Sunny Jul 25 '14 at 20:13
  • 2
    @Sunny you are right... also, we have to initialize the async object for async.delegate = this; to work.. – Ninja_Coder Jul 29 '14 at 13:16
  • Can the void processFinish() or whatever method you create be implemented in any Activity? or does it have to be the Activity that implements the ASYNCTASK? – Coova Oct 23 '14 at 15:57
  • Here is a extended example of [protocols](http://stackoverflow.com/a/26820666/2835520) – IgniteCoders Nov 08 '14 at 19:12
  • This worked so well and helped me restructure a bit of code that was getting a little out of control. Thanks! – Aaron Dec 30 '14 at 06:53
  • public void onPostExecute(HandleJSON data) { delegate.processFinish(data); at this step error occured. – Faisal Ashraf Mar 05 '15 at 17:30
  • I can't decide if this method is better, or the `new MyTask().execute().get()` one. Any suggestion will be much appreciated. – Solace Jun 28 '15 at 21:21
  • Why is it an accepted answer, if it is not workable and incomplete? Still not clear of how to solve nullpointer exception. Even if we create a constructor (as Sunny proposed) in asyncTask class, then how do we call this constructor? – Ayaz Alifov Jul 22 '15 at 16:35
  • 1
    Thank you so much. this is the only solution which i find robust, i tried everything...even google documentation says to use get method to get return values but it ends the async and UI starts hanging...this is the best solution..Clean and Clever.. Made my day :) – Karan Datwani Nov 20 '15 at 19:25
  • @KaranDatwani Would like to know, which option you prefer ? the first or second solution? – HelmiB Nov 22 '15 at 07:00
  • @HelmiB Boss i am using your line of code but i am facing some problem with your code because i want to use string variable result in on create method which is in processFinish method in main activity java file and in on create method it give null object reference when i use to "c = new JSONArray(resultofasync);" – Bhunnu Baba Dec 17 '15 at 06:31
  • @HelmiB I'm also getting a null pointer. I implemented the updated version of your solution. Any thoughts? – jason adams Jan 14 '16 at 16:46
  • 2
    just a side note create a weak reference of listener (Activity) in the AsyncTask class and check if not null on post execute to avoid memory leaks – Saqib May 16 '17 at 11:04
  • Is there a generic name for this pattern? Are there other ways to achieve this? From an Object Oriented thinking, how can I think about this solution from scratch? – Sreekanth Karumanaghat May 16 '18 at 13:16
  • What Is the disadvantage with using a class level variable at the activity and accessing it inside the Asynctask? – Sreekanth Karumanaghat May 16 '18 at 13:18
  • I thought the same thing! i was actually writing this solution, then i came to see if it is a better solution but i guess i was in the right path – GabrielBB Nov 17 '18 at 13:52
  • I am getting the error "Inner classes cannot have static declarations" – mad_greasemonkey Dec 11 '18 at 04:38
  • Could it be possible to update data in AsyncTask to its `LiveData<...>` member and adding an observer to observe data changes? – O-9 May 06 '19 at 09:22
  • I get this error when I follow your steps (the second one): "attempting to assign weaker access privileges; was public". could you clarify whats wrong? Thanks – Ashim May 18 '20 at 05:48
25

There are a few options:

  • Nest the AsyncTask class within your Activity class. Assuming you don't use the same task in multiple activities, this is the easiest way. All your code stays the same, you just move the existing task class to be a nested class inside your activity's class.

    public class MyActivity extends Activity {
        // existing Activity code
        ...
    
        private class MyAsyncTask extends AsyncTask<String, Void, String> {
            // existing AsyncTask code
            ...
        }
    }
    
  • Create a custom constructor for your AsyncTask that takes a reference to your Activity. You would instantiate the task with something like new MyAsyncTask(this).execute(param1, param2).

    public class MyAsyncTask extends AsyncTask<String, Void, String> {
        private Activity activity;
    
        public MyAsyncTask(Activity activity) {
            this.activity = activity;
        }
    
        // existing AsyncTask code
        ...
    }
    
quietmint
  • 13,885
  • 6
  • 48
  • 73
  • In the second option: Why go through the pain of a constructor and a field if the class is not `static`? Just use any `fieldOrMethod` from `MyActivity` or `MyActivity.this.fieldOrMethod` if it's shadowed. – TWiStErRob Dec 11 '14 at 23:32
  • @TWiStErRob The second assumes `MyAsyncTask` is *not* an inner class. – quietmint Feb 23 '15 at 20:24
  • 1
    Oh, sorry, `private`/`protected` for top level classes is not allowed, hence I thought it must be a non-`static` inner class. – TWiStErRob Feb 23 '15 at 21:33
  • 2
    Just be careful that inner class AsyncTask can be a source of memory leaks as explained here http://garena.github.io/blog/2014/09/10/android-memory-leaks/ – Mark Pazon May 01 '15 at 15:11
  • 2
    Holding onto an Activity reference is also a memory leak. The callback approach is far better than this – OneCricketeer Jul 17 '16 at 16:25
19

I felt the below approach is very easy.

I have declared an interface for callback

public interface AsyncResponse {
    void processFinish(Object output);
}

Then created asynchronous Task for responding all type of parallel requests

 public class MyAsyncTask extends AsyncTask<Object, Object, Object> {

    public AsyncResponse delegate = null;//Call back interface

    public MyAsyncTask(AsyncResponse asyncResponse) {
        delegate = asyncResponse;//Assigning call back interfacethrough constructor
    }

    @Override
    protected Object doInBackground(Object... params) {

      //My Background tasks are written here

      return {resutl Object}

    }

    @Override
    protected void onPostExecute(Object result) {
        delegate.processFinish(result);
    }

}

Then Called the asynchronous task when clicking a button in activity Class.

public class MainActivity extends Activity{

    @Override
    public void onCreate(Bundle savedInstanceState) {

    Button mbtnPress = (Button) findViewById(R.id.btnPress);

    mbtnPress.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                MyAsyncTask asyncTask =new MyAsyncTask(new AsyncResponse() {

                    @Override
                    public void processFinish(Object output) {
                        Log.d("Response From Asynchronous task:", (String) output);

                        mbtnPress.setText((String) output);
                   }
                });

                asyncTask.execute(new Object[] { "Your request to aynchronous task class is giving here.." });


            }
        });

    }



}

Thanks

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Arshad
  • 945
  • 9
  • 11
19

You can try this code in your Main class. That worked for me, but i have implemented methods in other way

try {
    String receivedData = new AsyncTask().execute("http://yourdomain.com/yourscript.php").get();
} 
catch (ExecutionException | InterruptedException ei) {
    ei.printStackTrace();
}
Nicu P
  • 253
  • 2
  • 6
  • 2
    Can you please explain why this would help OP with their issue? – John Odom May 27 '15 at 14:26
  • 3
    That helped me. I tryed in other way like the answer from @HelmiB but i get no results – Nicu P May 27 '15 at 15:09
  • Ok sorry for my answer. She need to call the AsyncTask class, and then to put a parameter to this call. AsyncTask is defined by 3 generic types: 1 params(server domain or other param) 2 progress(can be void), 3 result. All of these types can be: JSONObject, or strings, or any data types. When you have a AsyncTask class you should define where to send the data. ex: asyncTask.execute("https://sampletargeturl.com").get(); – Nicu P May 27 '15 at 15:42
  • When using this method, I got a warning on Logcat: "I/Choreographer﹕ Skipped 50 frames! The application may be doing too much work on its main thread." How to deal with this? Does UI get freeze when waiting for returned from AsyncTask? – Huy Do Jul 31 '15 at 03:37
  • @NicuP you might forgot to call `execute()`, see my answer, I've added comment there. you might want to check my updated answer. hope this helps. – HelmiB Nov 04 '15 at 05:00
17

This answer might be late but I would like to mention few things when your Activity dependent on AsyncTask. That would help you in prevent crashes and memory management. As already mentioned in above answers go with interface, we also say them callbacks. They will work as an informer, but never ever send strong reference of Activity or interface always use weak reference in those cases.

Please refer to below screenshot to findout how that can cause issues.

enter image description here

As you can see if we started AsyncTask with a strong reference then there is no guarantee that our Activity/Fragment will be alive till we get data, so it would be better to use WeakReference in those cases and that will also help in memory management as we will never hold the strong reference of our Activity then it will be eligible for garbage collection after its distortion.

Check below code snippet to find out how to use awesome WeakReference -

MyTaskInformer.java Interface which will work as an informer.

public interface MyTaskInformer {

    void onTaskDone(String output);

}

MySmallAsyncTask.java AsyncTask to do long running task, which will use WeakReference.

public class MySmallAsyncTask extends AsyncTask<String, Void, String> {

    // ***** Hold weak reference *****
    private WeakReference<MyTaskInformer> mCallBack;

    public MySmallAsyncTask(MyTaskInformer callback) {
        this.mCallBack = new WeakReference<>(callback);
    }

    @Override
    protected String doInBackground(String... params) {

        // Here do whatever your task is like reading/writing file
        // or read data from your server or any other heavy task

        // Let us suppose here you get response, just return it
        final String output = "Any out, mine is just demo output";

        // Return it from here to post execute
        return output;
    }

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);

        // Here you can't guarantee that Activity/Fragment is alive who started this AsyncTask

        // Make sure your caller is active

        final MyTaskInformer callBack = mCallBack.get();

        if(callBack != null) {
            callBack.onTaskDone(s);
        }
    }
}

MainActivity.java This class is used to start my AsyncTask implement interface on this class and override this mandatory method.

public class MainActivity extends Activity implements MyTaskInformer {

    private TextView mMyTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mMyTextView = (TextView) findViewById(R.id.tv_text_view);

        // Start your AsyncTask and pass reference of MyTaskInformer in constructor
        new MySmallAsyncTask(this).execute();
    }

    @Override
    public void onTaskDone(String output) {

        // Here you will receive output only if your Activity is alive.
        // no need to add checks like if(!isFinishing())

        mMyTextView.setText(output);
    }
}
Rahul
  • 10,457
  • 4
  • 35
  • 55
7

You can do it in a few lines, just override onPostExecute when you call your AsyncTask. Here is an example for you:

new AasyncTask()
{
    @Override public void onPostExecute(String result)
    {
       // do whatever you want with result 
    }
}.execute(a.targetServer);

I hope it helped you, happy codding :)

Ayaz Alifov
  • 8,334
  • 4
  • 61
  • 56
6

in your Oncreate():

`

myTask.execute("url");
String result = "";
try {
      result = myTask.get().toString();
} catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
}catch (ExecutionException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();

}`

user3691697
  • 71
  • 1
  • 2
4

You can call the get() method of AsyncTask (or the overloaded get(long, TimeUnit)). This method will block until the AsyncTask has completed its work, at which point it will return you the Result.

It would be wise to be doing other work between the creation/start of your async task and calling the get method, otherwise you aren't utilizing the async task very efficiently.

nicholas.hauschild
  • 42,483
  • 9
  • 127
  • 120
4

Why do people make it so hard.

This should be sufficient.

Do not implement the onPostExecute on the async task, rather implement it on the Activity:

public class MainActivity extends Activity 
{

@Override
public void onCreate(Bundle savedInstanceState) {

    //execute the async task 
    MyAsyncTask task = new MyAsyncTask(){
            protected void onPostExecute(String result) {
                //Do your thing
            }       

    }

    task.execute("Param");

}


}
bugdayci
  • 948
  • 7
  • 15
  • This works for me. It is the simple and the easiest to understand. I think it is making use of what Java is designed to do. Thanks. PS: Is it necessary to add an `@Override`? – Old Geezer Sep 15 '17 at 02:52
  • 1
    No. @Override is just an annotation. So you are telling java compiler that you are intending to override the method and get informed if you are not doing so. – bugdayci Sep 18 '17 at 10:56
3

You can write your own listener. It's same as HelmiB's answer but looks more natural:

Create listener interface:

public interface myAsyncTaskCompletedListener {
    void onMyAsynTaskCompleted(int responseCode, String result);
}

Then write your asynchronous task:

public class myAsyncTask extends AsyncTask<String, Void, String> {

    private myAsyncTaskCompletedListener listener;
    private int responseCode = 0;

    public myAsyncTask() {
    }

    public myAsyncTask(myAsyncTaskCompletedListener listener, int responseCode) {
        this.listener = listener;
        this.responseCode = responseCode;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }


    @Override
    protected String doInBackground(String... params) {
        String result;
        String param = (params.length == 0) ? null : params[0];
        if (param != null) {
            // Do some background jobs, like httprequest...
            return result;
        }
        return null;
    }

    @Override
    protected void onPostExecute(String finalResult) {
        super.onPostExecute(finalResult);
        if (!isCancelled()) {
            if (listener != null) {
                listener.onMyAsynTaskCompleted(responseCode, finalResult);
            }
        }
    }
}

Finally implement listener in activity:

public class MainActivity extends AppCompatActivity implements myAsyncTaskCompletedListener {

    @Override
    public void onMyAsynTaskCompleted(int responseCode, String result) {

        switch (responseCode) {
            case TASK_CODE_ONE: 
                // Do something for CODE_ONE
                break;
            case TASK_CODE_TWO:
                // Do something for CODE_TWO
                break;
            default: 
                // Show some error code
        }        
    }

And this is how you can call asyncTask:

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Some other codes...
        new myAsyncTask(this,TASK_CODE_ONE).execute("Data for background job");
        // And some another codes...
}
Community
  • 1
  • 1
Kuvalya
  • 1,094
  • 1
  • 15
  • 26
2

Hi you can make something like this:

  1. Create class which implements AsyncTask

    // TASK 
    public class SomeClass extends AsyncTask<Void, Void, String>>
    {
    
        private OnTaskExecutionFinished _task_finished_event;
    
        public interface OnTaskExecutionFinished
        {
            public void OnTaskFihishedEvent(String Reslut);
        }
    
        public void setOnTaskFinishedEvent(OnTaskExecutionFinished _event)
        {
            if(_event != null)
            {
                this._task_finished_event = _event;
            }
        }
    
        @Override
        protected void onPreExecute()
        {
            super.onPreExecute();
    
        }
    
        @Override
        protected String doInBackground(Void... params)
        {
            // do your background task here ...
    
            return "Done!";
        }
    
        @Override
        protected void onPostExecute(String result)
        {
            super.onPostExecute(result);
            if(this._task_finished_event != null)
            {
                this._task_finished_event.OnTaskFihishedEvent(result);
            }
            else
            {
                Log.d("SomeClass", "task_finished even is null");
            }
        }
    }
    
  2. Add in Main Activity

    // MAIN ACTIVITY
    public class MyActivity extends ListActivity
    {
       ...
        SomeClass _some_class = new SomeClass();
        _someclass.setOnTaskFinishedEvent(new _some_class.OnTaskExecutionFinished()
        {
        @Override
        public void OnTaskFihishedEvent(String result)
        {
            Toast.makeText(getApplicationContext(),
                    "Phony thread finished: " + result,
                    Toast.LENGTH_SHORT).show();
        }
    
       });
       _some_class.execute();
       ...
     }
    
1

Create a static member in your Activity class. Then assign the value during the onPostExecute

For example, if the result of your AsyncTask is a String, create a public static string in your Activity

public static String dataFromAsyncTask;

Then, in the onPostExecute of the AsyncTask, simply make a static call to your main class and set the value.

MainActivity.dataFromAsyncTask = "result blah";

mrres1
  • 1,147
  • 6
  • 10
0

I make it work by using threading and handler/message. Steps as follow: Declare a progress Dialog

ProgressDialog loadingdialog;

Create a function to close dialog when operation is finished.

   private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        loadingdialog.dismiss();

    }
    };

Code your Execution details:

 public void startUpload(String filepath) {
    loadingdialog = ProgressDialog.show(MainActivity.this, "Uploading", "Uploading Please Wait", true);
    final String _path = filepath;
    new Thread() {
        public void run() {
            try {
                UploadFile(_path, getHostName(), getPortNo());
                handler.sendEmptyMessage(0);

            } catch (Exception e) {
                Log.e("threadmessage", e.getMessage());
            }
        }
    }.start();
}
RAY
  • 2,201
  • 2
  • 19
  • 18
0

You need to use "protocols" to delegate or provide data to the AsynTask.

Delegates and Data Sources

A delegate is an object that acts on behalf of, or in coordination with, another object when that object encounters an event in a program. (Apple definition)

protocols are interfaces that define some methods to delegate some behaviors.

Here is a complete example!!!

IgniteCoders
  • 4,834
  • 3
  • 44
  • 62
0

try this:

public class SomAsyncTask extends AsyncTask<String, Integer, JSONObject> {

    private CallBack callBack;

    public interface CallBack {
        void async( JSONObject jsonResult );
        void sync( JSONObject jsonResult );
        void progress( Integer... status );
        void cancel();
    }

    public SomAsyncTask(CallBack callBack) {
        this.callBack = callBack;
    }

    @Override
    protected JSONObject doInBackground(String... strings) {

        JSONObject dataJson = null;

        //TODO query, get some dataJson

        if(this.callBack != null)
            this.callBack.async( dataJson );// asynchronize with MAIN LOOP THREAD

        return dataJson;

    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);

        if(this.callBack != null)
            this.callBack.progress(values);// synchronize with MAIN LOOP THREAD

    }

    @Override
    protected void onPostExecute(JSONObject jsonObject) {
        super.onPostExecute(jsonObject);

        if(this.callBack != null)
            this.callBack.sync(jsonObject);// synchronize with MAIN LOOP THREAD
    }

    @Override
    protected void onCancelled() {
        super.onCancelled();

        if(this.callBack != null)
            this.callBack.cancel();

    }
}

And usage example:

public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);

         final Context _localContext = getContext();
         SomeAsyncTask.CallBack someCallBack = new SomeAsyncTask.CallBack() {

                @Override
                public void async(JSONObject jsonResult) {//async thread
                    //some async process, e.g. send data to server...
                }

                @Override
                public void sync(JSONObject jsonResult) {//sync thread
                    //get result...

                    //get some resource of Activity variable...
                    Resources resources = _localContext.getResources();
                }

                @Override
                public void progress(Integer... status) {//sync thread
                    //e.g. change status progress bar...
                }

                @Override
                public void cancel() {

                }

            };

            new SomeAsyncTask( someCallBack )
                                .execute("someParams0", "someParams1", "someParams2");

    }
amiron
  • 721
  • 9
  • 11
0

Probably going overboard a bit but i provided call backs for both the execution code and the results. obviously for thread safety you want to be careful what you access in your execution callback.

The AsyncTask implementation:

public class AsyncDbCall<ExecuteType,ResultType> extends AsyncTask<ExecuteType, Void,  
ResultType>
{
    public interface ExecuteCallback<E, R>
    {
        public R execute(E executeInput);
    }
    public interface PostExecuteCallback<R>
    {
        public void finish(R result);
    }

    private PostExecuteCallback<ResultType> _resultCallback = null;
    private ExecuteCallback<ExecuteType,ResultType> _executeCallback = null;


    AsyncDbCall(ExecuteCallback<ExecuteType,ResultType> executeCallback, PostExecuteCallback<ResultType> postExecuteCallback)
    {
        _resultCallback = postExecuteCallback;
        _executeCallback = executeCallback;
    }

    AsyncDbCall(ExecuteCallback<ExecuteType,ResultType> executeCallback)
    {
        _executeCallback = executeCallback;
    }

    @Override
    protected ResultType doInBackground(final ExecuteType... params)
    {
        return  _executeCallback.execute(params[0]);
    }

    @Override
    protected void onPostExecute(ResultType result)
    {
        if(_resultCallback != null)
            _resultCallback.finish(result);
    }
}

A callback:

 AsyncDbCall.ExecuteCallback<Device, Device> updateDeviceCallback = new 
 AsyncDbCall.ExecuteCallback<Device, Device>()
    {
        @Override
        public Device execute(Device device)
        {
            deviceDao.updateDevice(device);
            return device;
        }
    };

And finally execution of the async task:

 new AsyncDbCall<>(addDeviceCallback, resultCallback).execute(device);
Squibly
  • 335
  • 2
  • 7
0

Hope you been through this , if not please read.

https://developer.android.com/reference/android/os/AsyncTask

Depending on the nature of result data, you should choose best possible option you can think of.

It is a great choice to use an Interface

some other options would be..

  • If the AsyncTask class is defined inside the very class you want to use the result in.Use a static global variable or get() , use it from outer class (volatile variable if necessary). but should be aware of the AsyncTask progress or should at least make sure that it have finished the task and result is available through global variable / get() method. you may use polling, onProgressUpdate(Progress...), synchronization or interfaces (Which ever suits best for you)

  • If the Result is compatible to be a sharedPreference entry or it is okay to be saved as a file in the memory you could save it even from the background task itself and could use the onPostExecute() method
    to get notified when the result is available in the memory.

  • If the string is small enough, and is to be used with start of an activity. it is possible to use intents (putExtra()) within onPostExecute() , but remember that static contexts aren't that safe to deal with.

  • If possible, you can call a static method from the onPostExecute() method, with the result being your parameter

Harsh
  • 363
  • 4
  • 14