I am developing an Android application which requires the use of AsyncTask for Network connection. I called it from the main thread. So the doInBackground method runs and then returns to the onPostExecute method. After the onPostExecute method is executed, I want to return a value back to the activity from where it was called, as I have to some operation in that particular activity which requires the value returned from onPostExecute method.
How do I solve this? How do I return a value from onPostExecute ?
Thanks in Advance
AsyncTask, as its name stated, is running asynchronously with UI thread, the onPostExecute method will be called at some point in the future, when doInBackground finished. We don't care when onPostExecute method will be called (actually there is no way to tell at project build time), the only thing we care is onPostExecute method is guaranteed to be called properly by underlying framework at some point in the future. So the purpose of onPostExecute method is for processing result returned from worker thread, this is also why the only argument of onPostExecute method is the result returned from doInBackground method.
I have to some operation in that particular activity which requires the value returned from onPostExecute method. How do I solve this?
Of cause, you can create some instance variables (or use listerner pattern) in the Activity class store the result when returned and ready in onPostExecute method. The problem is you never know when this result is ready outside onPostExecute method at project build time, as it is actually determined at app runtime. Unless you write some waiting mechanism continuously polling the result, which resulting sacrifice the benefit of AsyncTask, for instance, the built-in API AsyncTask.get() which makes AsyncTask running synchronously with UI thread and return the result to the Activity.
The best practice is change your design and move the operation code which requires the result returned from AsyncTask into onPostExecute method. hope this helps.
you can use getter and setter for getting value back from AsyncTask
public class MainActivity extends Activity {
public String retunnumfromAsyncTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layouttest);
new Asyntask(this).execute();
}
public class Asyntask extends AsyncTask<Void, Void, String> {
private final Context Asyntaskcontext;
public Asyntask(Context context){
Asyntaskcontext = context;
}
#Override
protected void onPostExecute(String result) {
MainActivity mainactivity = (MainActivity) Asyntaskcontext;
mainactivity.retunnumfromAsyncTask = result;
super.onPostExecute(result);
}
}
}
Just write the AsyncTask class as inner class to your activity then, declare whatever the value you want to return as global. Was it helpful to you?
Related
There are 3 handler in my fragment all those contain AsyncTask, and the fragment contains an int value, for example 50. Here what I wanted to do is to compare those 3 int value (which I am fetching in those 3 AsyncTask in handler) with the int value defined in fragment. For example if AsyncTask in handler-1 gets 80, AsyncTask in handler-2 gets 10, AsyncTask in handler-3 gets 46, then I want to compare these 3 ints with that fragment int.
I forgot to tell that after comparison, mFragmentValue needed to update with new value from onPostExecute().
My code is big to post here, so here is an example:
class MyFragment{
int mFragmentValue = 50;;
void onViewCreated(){
handler1.post(calling AsyncTask here using runnable); //Here I get 80 in onPostExecute in MyAsyncTask, now I need to compare this 80 with mFragmentValue. These AsyncTasks are sub class of my fragment.
handler2.post(calling AsyncTask here using runnable); //Here I get 10 in MyAsyncTask, now I need to compare this 10 with mFragmentValue;
handler3.post(calling AsyncTask here using runnable); //Here I get 46 in MyAsyncTask, now I need to compare this 46 with mFragmentValue;
}
static class MyAsyncTask extend AsyncTask{
void onPostExecute(){
// getting int here.
//need to compare fetched int with mFragmentValue;
}
}
}
If you only need the value of mFragmentValue in MyAsyncTask, then you can pass it in directly:
class MyFragment{
int mFragmentValue = 50;;
void onViewCreated(){
AsyncTask task = new MyAsyncTask();
task.execute(mFragmentValue);
}
static class MyAsyncTask extend AsyncTask{
int mTaskValue;
void doInBackground(Integer...values) {
mTaskValue = values[0];
}
void onPostExecute(){
// Now use mTaskValue
}
}
}
Note that there is no need to use a Handler nor a Runnable with an AsyncTask. The purpose of a Handler is to facilitate communication between threads, but AsyncTask already takes care of this for you. In addition, doInBackground() already runs on its own thread and onPostExecute() runs on the main thread, so there is no need to create a Runnable.
If you need to change the value of mFragmentValue, then MyAsyncTask must have a reference to the Fragment. You can do this by making MyAsyncTask non-static or add a constructor which accepts a Fragment as a parameter (or some interface which your fragment implements). Either way, you must find another way to address the memory leak warning. One solution here to add a method to MyAsyncTask that you can call from onPause(), onStop(), or onDestroy(). Calling this method tells the AsyncTask that the Fragment reference will is no longer valid. Then the AsyncTask acts accordingly, probably by aborting its work in doInBackground().
I have an activity A with static variable s. I pass the activity instance to async task for some processing. Suppose, in the mean time activity is closed (garbage collected) by android OS and AsyncTask is running in background. In AsyncTask now it is trying to access A.s which is not available so, it throws an exception. Is there any Solution for this. Thanks in advance.
Stop the asyncTask when the activity is closed. So the asyncTask will not try to access the activity anymore.
Try the following, don't keep s as static just pass it to the doInBackground method and collect back the result from onPostExecute method .
private class someLongRunningOperation extends AsyncTask<ArrayList, Progress, Result>{
#Override
protected Result doInBackground(ArrayList... params) {
// TODO Auto-generated method stub
String s=params[0];
//Do operations on the data
...
return s;
}
}
Call:
someLongRunningOperation longTask= new someLongRunningOperation ();
longTask.execute(yourList1, yourList2, yourList3...);
Note that the problem that you described can also happen during the screen orientation changes, If you are using a fragment use
setRetainInstance(true);
to save your data across activity recreations.
Just add null checks to avoid the exception. Example:
if (A != null && A.s != null) {
// proceed with your attempt to update the A.s variable
}
I am new to android. I have written a asynctask class which takes one string as parameter. Asynctask class has two functions doinbackground and onpostexecute. doinbackground is doing a httppost and if the post is successful it is returning a string "Success" to onpostexecute or pasing "Failed" to onpostexecute.
In Mainactivity I am calling the Asyncclass like below:
new MyAsyncTask().execute(xmlFile);
But I need to get the string that doinbackground returns in my mainactivity as based on this status I need to update a database filed. Can anyone help me on this issue.
Hypothetically I want to do the below in MainActivity
////////////////////////
Run the asyncclass by passing a string;;;
if doinbackground returns "Success" update database
else don't update
///////////////////////////
Thanks
You can use interface as a callback to the activity.
You can check blackbelts answer in the below link
How do I return a boolean from AsyncTask?
Or you can make AsyncTask an inner class of activity and get the result in onPostExecute.
You have several ways. One is using a Handler, to intercommunicate the Activity with your AsyncTask. This would involve passing the Handler object from the Activity to the AsyncTask and storing it there, so you can later use it. more on this here.
Another way is using a BroadcastReceiver. You declare it where you want to use it (i.e., where you want to receive the data, in this case in your Activity) and you use sendBroadcast from the AsyncTask to the Activity. More on this here.
There are more ways, but this ones are the most widely used.
You could probably just do your database update in the doInBackground instead of the onPostExecute that way you have your result and whether or not the http call passed.
Or you could have the AsyncTask return a class with whether or not it succeeded and the result then deal with it in onPostExecute, but you're back on the UI thread at that point and might not want to block with a db update.
private class PostResult {
boolean succeeded;
String response;
}
private class PostAsync extends AsyncTask<String, String, PostResult> {
protected PostResult doInBackground(String... xmlToPost) {
PostResult result = new PostResult();
try {
//do you httpPost... with xmlToPost[0];
result.response = "your data back from the post...";
result.succeeded = true;
//get your string result
}catch (Exception ex){
result.succeeded = false;
}
// I would update the db right here,
// since it's still on the background thread
return result;
}
protected void onPostExecute(PostResult result) {
//you're back on the ui thread...
if (result.succeeded){
}
}
}
I have set up an async task that will get a list of countries from a wsdl and from the result i create a bunch of country objects and add the objects to an arraylist in the country class file.
I want to be able to run this async task that will populate the array list then from another view be able to call specific indexes from the array list based on what the user has selected.
i have tried creating a class that extends AsyncTask and i have inserted the same code from the gingerbread version of the app i created which worked fine because network actions could be ran from the main thread
The type getWSDL2 must implement the inherited abstract method AsyncTask.doInBackground(Object...)
i dont have any objects to pass to this i all variables and stuff to get the wsdl data is within the async task and all the data i need from it is assigned to the arraylist from within the async task.
public class getWSDL2 extends AsyncTask {
protected void doInBackground()
{
........
}
Pass Void... as a parameter for doInBackground
protected void doInBackground(Void... params)
{
........
}
The way I understand your question you're not sure how to implement the AsyncTask because you have no need to pass values into it. All of the variables and data you need are included within the code that will execute the transaction with your server to download whatever it is you intend to display.
public class getWSDL2 extends AsyncTask {
protected Void doInBackground(Void... params) {
//All I/O code here
}
protected Void onPostExecute(){
//Anything that needs to run on the UI thread here
}
}
The general structure of the AsyncTask is listed above. The doInBackground method must contain any I/O functions while any thing you do tha touches a view, i.e. displaying the results of you're query as saved in a array list, must be called from onPostExecute, which runs on the UI thread.
From what I gather the solution is simple. Put all the code that is required for your server transaction within the doInBackground method. If you need to display the results of that transaction in a view just add a return statment to doInBackground and include the type of object/variable you will return in the varargs listed for the AsyncTask. For example if you were going to display the result of an ArrayList generated in your doInBackground method
public class getWSDL2 extends AsyncTask {
protected ArrayList<String> doInBackground(Void... params) {
//All I/O code here
return nameOfArrayListYouBuild
}
protected Void onPostExecute(ArrayList<String> whatever){
//use ArraList whatever to display your stuff
}
}
In the alternative if you don't need to display anything or run any functions on the UI thread then don't use the onPostExecute method at all.
public class getWSDL2 extends AsyncTask {
protected Void doInBackground(Void... params) {
//All I/O code here
return null
}
}
You can structure you're task so that it just uses doInBackground
Ok so now I have Class A that contains some spinners that values will be populated by Class B that extends AsnycTask which grabs the spinner values from a web service. In class B i manage to retrieve the values, showing in a Toast. The problem now is how do I pass those spinner values back to Class A?
I've tried
Can OnPostExcecute method in AsyncTask RETURN values?
by passing Class A to Class B and store the value in a public variable of Class A like below
#Override
protected void onPostExecute(String result)
{
classA.classAvariable = result;
}
However whenever I try to read the classAvariable i always get a NullPointer Exception.
Seems like the variable was never assigned with the result.
For readability purpose I needed to seperate Class B instead of using as an inline class.
Any ideas my fellow Java programmers?
Problem here is that when you execute your AsynchTask, its doInBackground() methode run in separate thread and the thread that have started this AsynchTask move forward, Thereby changes occur on your variable by AsynchTask does not reflect on parent thread (who stated this AsynchTask) immediately.
Example --
class MyAsynchTask
{
doInbackground()
{
a = 2;
}
}
int a = 5;
new MyAsynchTask().execute();
// here a still be 5
Create a interface like OnCompletRequest() then pass this to your ClassB constructor and simply call the method inside this interface such as complete(yourList list) in the method of onPostExecute(String result)
You can retrieve the return value of protected Boolean doInBackground() by calling the get() method of AsyncTask class :
E.g. you have AsyncTask class as dbClass like
dbClass bg = new dbClass(this);
String Order_id = bg.execute(constr,data).get();
Here I am passing constr as URL and data as string of inputs to make my class dynamic.
But be careful of the responsiveness of the UI, because get() waits for the computation to complete and will block the UI thread.