AsyncTask vs MainThread - java

Well I wrote a program which uses internet access and makes https requests. So i had to use AsyncTask to do the request part. My issue is that in my main activity, I have a function that increments a spinner after every https request made. In my backgroundTask(that is my AsyncTask class), i have included an static integer called :resultTest which numbers every exception generated. I just want to pass a value(either 0/1 or true/false) depending on if the connection was successful to my main thread. This value that will be passed will determine if I should increment the spinner or not.
Here is the the OnPostExecute part of my backgroundTask, just to give you an idea how it works:
#Override
protected void onPostExecute(String result) {
//this method will be running on UI thread
pdLoading.dismiss();
if (resultTest == 0) {
Toast.makeText(ctx,"Successfully Recorded",Toast.LENGTH_LONG).show();
}
else{
String msg = "";
switch(resultTest){
case 1:msg = "Internal App Error";
case 2:msg="Server Problem";
case 3:msg="Server Returned Error";
case 4:msg="Connection Problem";
}
Toast.makeText(ctx,msg,Toast.LENGTH_LONG).show();
}
}
Here is the part in my main thread where I instantiated the BackgroundTask and the event which depends on the value returned:
BackgroundTaskWater backgroundTaskWater = new BackgroundTaskWater(getActivity());
backgroundTaskWater.execute(field, val);
// FIX THIS INCREMENT
if(code == 0) {
meterItemIncrement(meters);
screen.setText("");
}
How can I pass the value of the variable resultTest in the backgroundTask to the variable code in the main thread?
I have tried to use static method and getter function but failed. The value doesn't get passed
I even tried to change the variable code in the main thread to public static and passed the value from the backgroundTask but when the backgroundTask gets destroyed, the value resets. the value does not get passed.
Any idea or suggestion will be greatly appreciated!!

Can't you move this code
if(code == 0) {
meterItemIncrement(meters);
screen.setText("");
}
to onPostExecute method?

In your asyncTask create interface object and assign it in constructor:
private OnResultCallBack onResultCallBack;
public BackgroundTaskWater (Context mContext, OnResultCallBack onResultCallBack) {
this.mContext = mContext;
this.onResultCallBack= onResultCallBack;
}
Now, in onPostExecute() process you message if success or not and pass it as parameter in interface:
if (this.onResultCallBack != null) {
this.onResultCallBack.onSuccess(msg);
}
NOTE: you also have to create an interface with parameter you want as result as:
public interface OnResultCallBack{
void onSuccess(String msg);
}
while creating object of your asyncTask:
BackgroundTaskWater backgroundTaskWater = new BackgroundTaskWater(getActivity(), new OnResultCallback() {
#Override
public void onSuccess(String msg) {
// HERE YOU WILL GET YOU MESSAGE!! (AS IN MAIN THREAD)
// IF YOU WANT STATUS CODE HERE, ADD SECOND PARAMETER IN interface
}
});
backgroundTaskWater.execute(field, val);

Related

Best way to get result from an AsyncTask to the caller class

I have implemented a way of getting the result from onPostExecute back to my main activity. I wanted to know if this is the right thing I did, is there any more chance of improving it, and if it's not the best way, what is the best way?
This is what I have done:
public class MainClass implements AsyncResponse {
private MyAsyncTask asyncTask;
public MainClass() {
asyncTask = new MyAsyncTask();
asyncTask.asyncResponse = this;
}
public void startTask( {
asyncTask.execute("string");
}
#Override
public void processDone(String res) {
// got response in MainClass from onPostExecute
}
private class MyAsyncTask extends AsyncTask<String, String, String> {
protected AsyncResponse asyncResponse = null;
#Override
protected String doInBackground(String... urls) {
return "some processed string";
}
#Override
protected void onPostExecute(String res) {
this.asyncResponse.processDone(res);
}
}
}
Here's the AsyncResponse interface:
public interface AsyncResponse {
void processDone(String res);
}
I want to know in terms of processing speed that on an average android mobile device, would this be a good approach and if not, how do I improve it to make it a good approach?
Thanks.
I always done this way and never had any issues. I would say it is the best way.
in one Line without any callback
String s= new MyAsyncTask().execute().get();
You added an unnecessary interface - and perhaps it makes your code less usable.
First, if you create the AsyncTask as a class within your Activity there is no need for the interface. You can simply do this:
#Override
protected void onPostExecute(String res) {
processDone(res);
}
The AsyncTask will execute onPostExecute on the UI thread and you can call the Activity method without the interface.
Second, if you create AsyncTask outside the Activity class (for example, in its own java file) then you can use this method, except it is not a good idea because it will hold a reference to the Activity on another thread - it's a memory leak risk.
To avoid that, your interface should be implemented in a separate class, like AsyncTaskResponse.java that is passed to the AsyncTask class.
Last, AsyncTask provides the response in the form of a String if that is sufficient. You should look at the docs on AsyncTask:
https://developer.android.com/reference/android/os/AsyncTask.html
You are wrapping the AsyncTask inside another POJO class; doing this doesn't hurt, but provides little benefit.
Consider that when the task is completed, you will want a callback notification somewhere. Your MainClass will get a callback in processDone(), but something will need to be listening to MainClass to get that notification.
Here is a pattern I always use with my AsyncTask subclasses:
public class GetDataRemoteTask extends AsyncTask<String, Void, Data> {
private static final String TAG = "GetDataRemoteTask ";
private WeakReference<GetDataResultListener> mListenerRef;
private Exception mExc;
#Override
protected Data doInBackground(String... params) {
Data result = null;
try {
result = mService.getData(params[0], params[1], params[2]);
} catch (Exception e) {
Log.e(TAG, "Error occurred getting data", e);
mExc = e;
}
return result;
}
#Override
protected void onPostExecute(Data result) {
if (mListenerRef != null) {
GetDataResultListener listener = mListenerRef.get();
if (listener != null) {
if (mExc == null) {
listener.dataReceived(result);
} else {
listener.dataException(mExc);
}
}
}
}
public void setGetDataResultListener(GetDataResultListener listener) {
if (listener == null) {
this.mListenerRef = null;
} else {
this.mListenerRef = new WeakReference<GetDataResultListener >(listener);
}
}
public static interface GetDataResultListener {
public void dataReceived(Data data);
public void dataException(Exception exc);
}
}
So to start off, here I have an interface, like you do, for connecting to the AsyncTask. But I don't wrap my AsyncTask with an implementation, I expect that I will have an Activity or a Fragment that will implement this interface. (That's why I use a WeakReference; if the Activity finishes, my AsyncTask won't keep holding on to the Activity. But that also means I can't use an anonymous class listener unless the client holds the reference for it.)
My client code will look like this:
GetDataRemoteTask task = new GetDataRemoteTask();
task.setListener(this);
task.execute(param1, param2, param3);
I also have a way to find out if there was an exception that occurred in the background task. Any background exceptions should always be reported to the client, which can decide how best to deal with the exception - for example pop up a dialog for the user, so they know the request failed.
I think that a big drawback of AsyncTask is that it doesn't have more structure around handling exceptions that occur in the background thread.
My task holds a reference to the exception, but I have also used Pair<Data, Exception> as a type parameter for return result so I don't need the exception property.
Using this pattern has helped me avoid some typical problems that occur when coding AsyncTask subclasses.

Activity collides with AsyncTask? How to implement AsyncTask into GUI?

I am sorry for my bad english skills. I'm new to programming/stackoverflow and try to create a little android quiz app. This app has to connect to a php server and login/getquestion...
The simplest example is the login. The user has to type in his data and then i have to connect.
To provide that the Gui doesnt freeze i have to use asynchronous tasks.
Here the activity's code:
public void login(final String username, final String password) {
final Activity a = this;
FutureTask t = new FutureTask(new Callable() {
public Object call() {
Connection.GetInstance(a).login(username,password);
afterLoginTry(username,password);
return null;
}
});
t.run();
}
This calls a method in another class, which calls another FutureTask which calls an AsyncTask. At the end there is always an public synchronized method such as afterlogintry(). This works but it's a bit slow and i think dirty code.
My main problem is that i don't know how to give results back through different layers of classes and especially to the activity without using hotfixes all the time.
Is there any good explanation or tutorial, which describes how to design such a construct?
Thx for help
The way you can pass AsyncTask results back to other classes, is by declaring callbacks for the task, that will then report the result to a listener. Here is how it works.
First, you must declare an interface in your AsyncTask which contains a method that will send out the result of the task. So in my example task below, my result is a String. The String gets passed to onPostExecute() when the task finishes its work. I then call my callback method on a registered listener, and pass that return value on to whoever is listening for it. You register a listener by passing in an instance of your callbacks from whichever class is creating the task.
public class MyTask extends AsyncTask<String, Void, String> {
MyTaskCallback listener;
public MyTask(MyTaskCallback listener) {
this.listener = listener;
}
protected String doInBackground(String... params) {
String input = params[0];
//do work
input += "did some work on this String";
return input;
}
//When the thread finishes its work, this gets
//called on the main UI thread
protected void onPostExecute(String result) {
listener.onResultReceived(result);
}
public interface MyTaskCallback {
void onResultReceived(String result);
}
}
So next we need to register a listener for these callbacks, so when the result comes in from the task, it will get reported directly to our class. So let's say we have a simple Activity. The way we register the callbacks is to use the implements keyword on our class declaration, and then to actually implement the callback method in the class itself. We then create our task, and we pass in this which is our Activity that implements the callbacks. A simple example Activity that does this looks like this:
public class TaskActivity extends AppCompatActivity implements MyTask.MyTaskCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
//we pass in "this" because our Activity itself
//implements the callbacks below.
MyTask myTask = new MyTask(this);
myTask.execute();
}
//Here we implement our callback method, so the task
//can send its results straight through here
public void onResultReceived(String theResult) {
Log.d("TASK RESULT", "Here is our result String: "+theResult);
}
}
Now, our task has our Activity connected to it, through the callbacks we passed into it. So now when our task gets a result, we can send it directly to our listener, which is our Activity, and the result will come right through to our implemented onResultReceived method.
Callbacks are a great way to pass information around between classes while also keeping everything very separated. Hope this helps!

Asynctask ArrayList object not passing from doInBackground to onPostExecute

I have an AsyncTask that takes in context (used onPostExecute) and runs doInBackground to return an ArrayList of objects from a server. When I execute this I can see that doInBackground runs fine, however it is not passing the result on to onPostExecute.
After much searching, I have yet to find an answer of how to return an ArrayList of objects in an AsyncTask.
This is the object I'm creating in doInBackground and using onPostExecute:
public class ServerTimeCard {
public String eventNameInput;
Boolean isLocation, isImage, isVoice;
public ServerTimeCard(String eventNameInput, boolean isLocation, boolean isImage, boolean isVoice) {
this.eventNameInput = eventNameInput;
this.isLocation = isLocation;
this.isImage = isImage;
this.isVoice = isVoice;
}
}
I'm executing the AsyncTask with new LoadFriendCards(context).execute(); in onCreate.
Expected Output: doInBackground should return an ArrayList to onPostExecute
Current Output: The ArrayList<ServerTimeCard> in onPostExecute has a size of zero when the same arraylist in doInBackground has a larger size.
The following is the AsyncTask code.
public class LoadFriendCards extends AsyncTask<Void, Void, ArrayList<ServerTimeCard>> {
Context context;
ArrayList<ServerTimeCard> result;
public LoadFriendCards(Context context) {
this.context = context;
}
#Override
protected ArrayList<ServerTimeCard> doInBackground(Void... voids) {
result = new ArrayList<ServerTimeCard>();
// ...a bunch of data retrieval goes on here...
// querying parse for object info
// adding a new object to the local ArrayList for all in db
for (String friend : friendsListNames) {
ParseQuery<ParseObject> query = ParseQuery.getQuery("TestObject");
query.whereEqualTo("accountName", friend+"#gmail.com");
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> objects, ParseException e) {
if (e == null) {
for (ParseObject cardInfo : objects) {
ServerTimeCard item = new ServerTimeCard(
cardInfo.getString("eventName"),
cardInfo.getBoolean("isImage"),
cardInfo.getBoolean("isImage"),
cardInfo.getBoolean("isVoice"));
result.add(item);
Log.e("New item called: ", String.valueOf(item.eventNameInput));
Log.e("New size of array...", String.valueOf(result.size()));
}
} else {
Log.d("info", "Error: " + e.getMessage());
}
}
});
}
// returning the new ArrayList<ServerTimeCard> to onPostExecute
// PROBLEM: THE SIZE OF THE RESULT IS 0
Log.e("Size of passing array", String.valueOf(result.size()));
return result;
}
#Override
protected void onPostExecute(ArrayList<ServerTimeCard> result) {
// PROBLEM: This returns 0
Log.e("Data list size: ", String.valueOf(result.size()));
// trying to use all objects in the arraylist here but it doesn't work
// due to the size. Something isn't passing correctly.
}
}
Logcat output of Log.e: (which looks like it calls doInBackground, then onPostExecute, then doInBackground again)
E/Size of passing array﹕ 0
E/Data list size:﹕ 0
E/New item called:﹕ yah
E/New size of array...﹕ 1
E/New item called:﹕ lplokolol
E/New size of array...﹕ 2
E/New item called:﹕ It works
E/New size of array...﹕ 3
SOLVED: I originally thought I needed the AsyncTask but I ended up deleting it all and throwing all the code into a method in my Main class. I was running too many things at once in an asynctask and the structure was throwing data all over the place. Lesson learned: keep it simple.
Your issue is that you are using findInBackground for your query. That method is done in a background thread. So you're basically running an async task, within an async task.
doInBackground
findInBackground -> run asynchronously so code execute continues
onPostExecute is called before your query finishes.
The done call back is then called for your query to fill your list
So what you need to do instead is either use findInBackground outside of an AsyncTask (that method is intended to not be used in an AsyncTask) or use the find function.
You're modifying result in an anonymous inner class. Your code there doesn't see the result you think it sees, but rather a closure. This is the root of the problem.
You are starting a background thread (your async task), and here you call query.findInBackground() multiple times which starts MORE background threads. This, however, isn't a problem.
You're getting problems because the AsyncTask is done before all the other threads it started have finished. You only know the other threads are done when each of their FindCallback's done() method is called.
If you want to know the correct size, you need to code it in a way so that you check the size in the last done() method.
You dont have to make doInBackground to return an arraylist which can be used in onPostExecute. Just return "ok" or "error". Declare and create a private arraylist as member of your ask. Then fill it in doInBackground and use it in onPostexecute.
An alternative and simpler way is to declare your doInBackground as List type.
Here is my Example
#Override
protected ArrayList<ServerTimeCard > doInBackground(String... urls) {
// Perform the HTTP request for earthquake data and process the response.
ArrayList<ServerTimeCard > result = QueryUtils.fetchTheData(urls[0]);
return result;
}

return function value after AsynTask finished his work

i have a function that return an String and has an AsynTask inside it. my problem is that my function have to return the value after AsynTask finished his work!
this is my code:
public String getWeather(Context cont,int cityid,String latitude, String longitude){
this.latitude=latitude;
this.longitude=longitude;
new get_scores() {
protected void onPreExecute() {
super.onPreExecute();
}
protected void onPostExecute(Boolean result) {
}
}.execute();
return weatherdata;
}
i want to return weatherdata but after finishing AsynTask. it can be take a few seconds.
One solution is to return the value from `onPostExecute(). You can do this by setting up your AsyncTask as normal then change your return statement to something like
public String getWeather(Context cont,int cityid,String latitude, String longitude){
this.latitude=latitude;
this.longitude=longitude;
new get_scores() {
protected void onPreExecute() {
super.onPreExecute();
}
protected void onPostExecute(Boolean result) {
}
}.execute();
return new get_scores().execute();
}
Doing it this way you will probably want to add a progress bar/dialog so that the user doesn't think the app is stuck. As long as the task doesn't take more than 2 or 3 seconds(at most) and you don't want the user to be able to do anything else until it finishes then this should be fine to do. And I would have some error checking by surrounding with a try/catch or make sure you return something in case the app can't return
The reason to create an AsyncTask is not to run on the UI thread.The return statement is part of the UI thread, so the return statement will always return null because it continue executing code when background thread s start.
You have two possibilities:
1-You run your code on the UI Tread and your app get stuck working in this function until it arrives at the return statement and returns the calculated value for the variable. Please, don't do that.
2-It is what I would do. Don't return anything from this function, so change it to return void, remove the return statement, call the asynctask and from onPostExecute you call a function that will manipulate the variable that you assigned value on doInBackground.
I don't see where you are doing doInBackground but there it is where the task must be done, so implement it and give in there the value to your variable not to be null again.

Weakreference get() method how safe is it? (Android, asynctask)

I am making an Android mobile app. I have a WeakReference to my Activity in the AsyncTask to ensure that it can be garbage collected.
When onPostExecute() gets called, I do
Acitivty activity = mWeakRef.get();
Then I use the activity object to display dialogs to the user etc etc.
My question is, as I am trying to determine which dialog to show and what to do, could my activity object become null? Could it ever become null if the GC runs in between my line of execution? Am I safe to keep using that object from the first get() or do I have to redo get() and check if the value is null right before I use it.
thanks!
It's safe!
As soon as you assign the result of get() to a variable, you have a strong reference again which blocks gargbage collection for this object as long as the new reference exists.
Of course, after this assignment you need to check if activity is null.
I think it's NOT safe. I get a NPE at activity.msgWebView.setVisibility(View.GONE); inside Handler.
```java
private static class HttpStatusHandler extends Handler {
private WeakReference<MessageWebViewActivity> activityWeakReference;
public HttpStatusHandler(WeakReference<MessageWebViewActivity> activityWeakReference) {
this.activityWeakReference = activityWeakReference;
}
#Override
public void handleMessage(Message msg) {
MessageWebViewActivity activity = activityWeakReference.get();
if (activity != null) {
if (msg.what == MSG_URL_OK) {
activity.loadUrl(activity.url);
} else if (msg.what == MSG_URL_ERROR) {
activity.msgWebView.setVisibility(View.GONE);
activity.clPageError.setVisibility(View.VISIBLE);
activity.progressbarLayout.setVisibility(View.GONE);
}
}
}
}
```

Categories