How AsyncTask returns parameters to MainActivity - android

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){
}
}
}

Related

how to allow UI thread to wait for the background thread to finish?

I can use AsnycTask get() method to wait for the background task to be completed, But how do I do it if I'm using CursorLoader and ContentProvider with LoaderManager Callback?
Is it also possible to prevent the UI thread from waiting for the data returned in the background thread?
You can easily pass your interface to get call back of Asynctask .This is right way to get solution of your problem
Show ProgressDialog to wait untill response is not receive. if your response is receiving from same class or activity then do not use interface call back, if response is receiving from other activity of class then use interface call back
Wait on UIThread is not recommended it makes app looks like laggy or stucked. blundell made good point in the edit.
I have exactly the same situation in one of my current project where i have to request the list of contacts using the content provider and cursor loaders to display them later on a listview.
So here is what you should do:
Make an Async call to the content provider from whithin your activity/fragment using the async task as a static inner class.
Inside the AsyncTask doInBackground() method you place your function to retrieve the cursor and process your data there so you end up with returning a List<Object> Object is the returned Model (Contact) in my case.
Inside the AsyncTask's onPostExecute() method you just pass the retreived data list to whatever View you are working with (again in my case it's a List<Contact> and there where your mainThread is receiving data and only there it has to process the data when it's ready.
AsyncTask make your life much easier as they have a string structure to handle passing data from a MainThread to a background separate Thread and then ship back the data from the background Thread to the MainThread.
In terms of code your code should look like :
public class MainActivity extends Activity {
private AsyncTask mTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//
......
//Call the AsyncTask and pass your Data
mTask = new Task(this);
mTask.execute();
}
private static class Task extends AsyncTask<Void, Void, List<Object> {
private WeakReference<Contex> mContextRef;
public Task(Context context) {
mContextRef = new WeakReference<>(context);
//later when you need your context just use the 'get()' method. like : mContextRef.get() (this will return a Context Object.
}
#Override
protected void onPreExecute() {
// show progress Dialog
//this method is processed in the MainThread, though it can prepare data from the background thread.
}
#Override
protected List<Object> doInBackground(Void ... params) {
List<Object> mList = new ArrayList<>();
//Call your content provider here and gather the cursor and process your data..
//return the list of object your want to show on the MainThread.
return mList;
}
#Override
protected Void onPostExecute(List<Object> list) {
if(list.size() > 0) {
//do your stuff : i.e populate a listView
}
}
}
}

Android Fragment + AsyncTask

In a fragment I'm using an 'AsyncTask' to retrieve data from a URL. The main purpose of my code is to access the data (via AsyncTask) and to pass a 'JSONArray' to the fragment.
Problem is, on the fragment side, that when I check the variable that should have the result i get an error saying that the variable is null.
Here is the code:
public class MyFragment extends ListFragment {
//this is the variable that should have the result from the AsyncTask
JSONArray myResult = null;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
(...)
//execute the asyncTask
new GetResult().execute(email, password);
(...)
}
//The AsyncTask
private class GetResult extends AsyncTask<String, Void, JSONArray> {
#Override
protected JSONArray doInBackground(String... params) {
(...)
JSONArray jsonArray = (JSONArray) json.get("customer");
return jsonArray;
}
protected void onPostExecute(JSONArray result){
(...)
//this is where I try to pass the data to the fragment
MyFragment.this.myResult = result;
}
}
}
Can someone can help me with that? Thank you in advance.
Are you using the value after postExecute method. You should know that after calling execute, your code on the main thread still runs and only after postExecute has completed, will you have the value.
Try to use this code, and make sure that your jsonstring is not null, because you won't post your complete code and I can't see if myResult variable was changed:
try {
JSONArray json = new JSONArray(jsonstring);
JSONObject json_customer = json.getJSONObject("customer");
return json_customer;
} catch (JSONException e) {
return null
}
For me it looks like problem with deserialization from String data to json's. We are lack of information what exactly data you are parsing. Consider using for this some more advanced json processing library lika Gson or Jackson. Usually its easier with them.
It sounds like you are trying to read from myResult variable before the AsyncTask finishes retrieving it. To make sure it populates properly, put this into your onPostExecute function, after this line MyFragment.this.myResult = result;:
Log.i("my result value is: ", MyFragment.this.myResult.toString())
It should print it out in the LogCat if you are retrieving it correctly, and you should be able to access that variable after that.
On a separate note, consider using Volley or Retrofit or another networking plugin to make your life easier.
Maybe you can use a clear way to transfer data back from the task to the fragment.
1) define an interface as the event listener to be called in the AsyncTask, like
public interface TaskEventListener(){
public void onTaskStarted(int messageId);
public void onTaskStopped(int messageId, int resultCode);
public void onDataReady(Object parameter);
}
2) let the fragment implement this EventListener, put the processing code in the onDataReady() function.
3) pass the fragment instance as the EventListener instance.
4) in the class extended from the AsyncTask, call the onTaskStarted() in the onPreExecute() function, call the onDataReady() and onTaskStopped() in the onPostExecute() function, and call the onTaskStopped() only in the onCancelled() function.
5) please use the weak references in the background task class to prevent crashing for referring the invalid UI component.

Return value from AsyncTask class onPostExecute method

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.

Use Asynctask as a private class or with broadcast receiver?

I'm trying to make an application that uses Asynctask. Particularly, I want to make different http petitions with different JSON in different activities without the activity being frozen while the communication is done.
At first I thought to use asynctask as a private inner class in those activities, but I saw that they share a lot of code. So I thought to make a single class and play with broadcast receivers as I need to monitorize when I receive the result of the http petition, and isn't good to interfere with activity directly in the onPostExecute while in a different class.
What I want to know is, what is more efficient and better practice. Make a class that has the shared code and extends asynctask, then doing inner classes for each activity that extends that one or make a single asynctask that sends broadcast and receive them with each activity when needed.
Excuse my poor english, if needed I'll try to specify more clearly.
Thanks in advance
Background
What I want to know is, what is more efficient and better practice. Make a class that has the shared code and extends asynctask, then doing inner classes for each activity that extends that one or make a single asynctask that sends broadcast and receive them with each activity when needed.
I'm unclear as to why these are your only two options. Create a single AsyncTask, such as JsonPetitionTask, then push a new JsonPetitionTask.Data object. This object would contain your URL, your JSON, and any other data you need.
Setting up the AsyncTask
Something like this:
public class JsonPetitionTask extends AsyncTask<JsonPetitionTask.Data, Integer, Boolean> {
protected Boolean doInBackground(JsonPetitionTask.Data... args) {
for (int i = 0; i < args.length; i++) {
JsonPetitionTask.Data data = args[i];
// Send your JSON; check for errors, and return false if needed.
if (isCancelled()) break;
}
return true;
}
protected void onProgressUpdate(Integer... progress) {
// Show progress?
}
protected void onPostExecute(Boolean result) {
// result is your success true/false.
}
public static class Data {
public String jsonContent;
public String petitionUrl;
public Data(String content, String url) {
jsonContent = content;
petitionUrl = url;
}
}
}
Calling the JsonPetitionTask
Then you can call it like so:
JsonPetitionTask.Data data = new JsonPetitionTask.Data(myJSON, myURL);
new JsonPetitionTask().execute(data);
And voilĂ , you've executed your AsyncTask using only one class with no receivers.
Implementing a callback
Now, if you want to register a callback (something to execute that is specific to the calling code), that's a bit trickier. If this is part of what you're looking for, I'll be glad to edit this post and explain it.
To add a callback, we can use the Runnable class to execute some code after the job is done.
Firstly, we need to add a new field in the Data inner class:
public Runnable callback;
Next, before we call execute(), we need to add a new callback to our data object.
data.callback = new Runnable() {
public void run() {
// Whatever code you want to run on completion.
}
};
Third, in the JsonPetitionTask class, we need a list of things to run:
private ArrayList<Runnable> mRunnables = new ArrayList<Runnable>();
Make sure, in each iteration of the doInBackground() loop, that you do mRunnables.add(data.callback);.
Lastly, in onPostExecute(), we need to call this:
protected void onPostExecute(Boolean result) {
for (Runnable r : mRunnables)
if (r != null) r.run();
}
I do realize I didn't send result to the Runnable, however I didn't feel like implementing a new Runnable type just to handle that. If you need this, I guess that's a bit of homework for you!
The way I found the best is just simply create public class that extends AsyncTask and then you just override onPostExecute function in every activity you use it.
Example:
MyDataTask dataTask = new MyDataTask() //you can add your parameters in class constructor
{
#Override
protected void onPostExecute(Object result) //replace Object with your result type
{
MyActivity.this.doStuff(result); //use result in current activity
}
};
you can also create some custom functions to set private variables in datatask
dataTask.AddParam("user", username);
dataTask.AddParam("pass", pass);
and then just execute it with your args...
dataTask.execute(myArgs);
I have used Async task class as single class. And for every Webservice call i have used unique IntentFilter to Broadcast response.
Put that Broadcast receiver in every class. You have perfect solution.
Its working well.

Can OnPostExcecute method in AsyncTask RETURN values?

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?

Categories

Resources