Should I write smth like that
return task.exec(session, state).get(json_timeout, TimeUnit.MILLISECONDS);
Or I can do like this
task.exec(session, state, result);
return result;
A have already read all documentation that I found, but failed to find an answer. My bad...
Do not use get(). It will block the ui thread until asynctask finishes execution which no longer makes it asynchronous.
Use execute and to invoke asynctask
new task().exec(session, state, result);
Also you can pass the params to the constructor of asynctask or to doInbackground()
http://developer.android.com/reference/android/os/AsyncTask.html
public final Result get ()
Added in API level 3
Waits if necessary for the computation to complete, and then retrieves its result.
You can make your asynctask an inner class of your activity class and update ui in onPostExecute.
If asynctask is in a different file then you can use interface.
How do I return a boolean from AsyncTask?
AsyncTask#get() will block the calling thread.
AsyncTask#execute() will run in a separate thread and deliver the Result in onPostExecute(...).
I would recommend against using the get() method except in special cases like testing. The whole purpose of the AsyncTask is to execute some long-running operation in doInBackground() then handle the result once it's finished.
One example of normal AsyncTask execution would look like:
Task task = new Task(){
#Override
protected void onPostExecute(Result result) {
super.onPostExecute(result);
//handle your result here
}
};
task.execute();
Related
I am using below code to get result from Asynctask
Ui thread
.....
....
int result = new MyCustomTask().execute().get();
if (result == 1) {
}
else {
}
----
----
But my doubt is "Whats the point of having an async task when get() waits for it to complete"
No point in calling get().
Just have
new MyCustomTask().execute();
Calling get() blocks the ui thread waiting for the result. This makes AsyncTask no more Asynchronous.
The result of doInbackground computation is param to onPostExecute. So you can retrun result in doInbackground and update ui in onPostExecute.
You can use onPostExecute() to update ui if its a inner class of Activity or you can use interface as a callback to the activity to get the result.
Use interface as a callback
How do I return a boolean from AsyncTask?
The following were supposed to be the same if I am not mistaking.
Using AsyncTask:
private class GetDataTask extends AsyncTask<String, Void, String>{
#Override
protected void onPreExecute() {
}
#Override
protected String doInBackground(String... params) {
return NetConnection.getRecordData(mUserId, mUserPassword);
}
#Override
protected void onPostExecute(String result) {
parseJson(result);
}
}
Using a Thread:
new Thread( new Runnable() {
#Override
public void run() {
String res = NetConnection. getRecordData(mUserId, mUserPassword);
parseJson(res);
}
}).start();
But when uploading a file, the AsyncTask runs synchronously while the Thread run asynchronously(in parallel).
Why is so? Why AsyncTask behaves like this? Isn't AsyncTask supposed to run asynchronously?
I am little confused so I need your help.
This is how I invoke the GetDataTask:
new GetDataTask().execute()
I prefer using AsyncTask but it is not doing the job for me. Please refer to my early question for more details
As of 4.x calling 2 AsyncTasks will cause them to be executed serially.
One way to fix this is using the following code
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) {
myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
else {
myTask.execute();
}
You can read more at: http://commonsware.com/blog/2012/04/20/asynctask-threading-regression-confirmed.html
Ok following are the notes from the official java doc...
Order of execution
When first introduced, AsyncTasks were executed serially on a single
background thread. Starting with DONUT, this was changed to a pool of
threads allowing multiple tasks to operate in parallel. Starting with
HONEYCOMB, tasks are executed on a single thread to avoid common
application errors caused by parallel execution.
If you truly want parallel execution, you can invoke
executeOnExecutor(java.util.concurrent.Executor, Object[]) with THREAD_POOL_EXECUTOR.
SO if you invoke two AsyncTask together.. they would not be executed in parallel (exception is donut, encliar and gingerbread)... You can use executeOnExecutor to execute them in parallel...
From your code we can see you have called parseJson(result); in onPostExecute() of AsyncTask which runs in MainUIThread of Applications. So at that point your code runs Synchronously..
Put parseJson(result); method in doInBackGround() Which runs only in other worker thread.
While you have called same thing in Thread. So both
String res = NetConnection. getRecordData(mUserId, mUserPassword);
parseJson(res);
Runs in other worker thread out of MAinUiThread on which you experienced Asynchronously.
Note:
But be sure your parseJson(res); doesn't update UI while it is in doInBackground().
Looks like that actual problem is not in file uploading but in parseJson method.
In your Thread example you parsing Json in separate thread while in AsyncTask case you parsing Json in UI thread.
I have an AsyncTask updating an ActionBarSherlock progress implementation. Somehow the onProgressUpdate is throwing a threading error though it claims to execute on the UI thread.
protected void onProgressUpdate(Integer... values)
{
setSupportProgress(values[0]);
}
The error is:
03-06 00:13:11.672: E/AndroidRuntime(4183): at com.anthonymandra.framework.GalleryActivity$ShareTask.onProgressUpdate(GalleryActivity.java:476)
Only the original thread that created a view hierarchy can touch its
views.
As far as I can tell I should be accessing the UI thread for this...
I have many working AsyncTasks in my app, but as requested here's the doInBackground (simplified):
for (MediaObject image : toShare)
{
BufferedInputStream imageData = image.getThumbStream();
File swapFile = getSwapFile(...);
write(swapFile, imageData);
++completed;
float progress = (float) completed / toShare.size();
int progressLocation = (int) Math.ceil(progressRange * progress);
onProgressUpdate(progressLocation);
}
Okay so the problem is you are calling onProgressUpdate when you should call publishProgress. The OP figured out this himself/herself so I just copy pasted it so he/she does not need to wait to accept the answer. Below is information how AsyncTasks works and it is good knowledge.
Are you creating the AsyncTask on the UI thread? If you are not that is the problem. onProgressUpdate will be run on the thread that created the AsyncTask.
Update: Let us have some code digging time (API 15 source code)!
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
This fellow will call it's static Handler sHandler. The documentation says:
When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
Thanks to Bruno Mateus with his documentation look-up skills:
Look that, i found at documentation page: Threading rules - There are
a few threading rules that must be followed for this class to work
properly: - The AsyncTask class must be loaded on the UI thread. This
is done automatically as of JELLY_BEAN. - The task instance must be
created on the UI thread. execute(Params...) must be invoked on the UI
thread. - Do not call onPreExecute(), onPostExecute(Result),
doInBackground(Params...), onProgressUpdate(Progress...) manually. -
The task can be executed only once (an exception will be thrown if a
second execution is attempted.)
You can declare your AsyncTask as a innerclass of your activity like that:
public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask {
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}
I was manually calling:
onProgressUpdate
You should call
publishProgress
Easy mistake, but great info. Simon and Bruno deserve the credit, post the answer if you like. Thanks for the fast and extensive response!
I want to cancel the Async Task on the particular condition.
I am doing the following stuff:
MyService.java
....
if(condition){
asyncTask.cancel(true); // its return the true as well
}
...
MyAsynTask.java
...
protected Object doInBackground(Object... x) {
while (/* condition */) {
// work...
if (isCancelled()){ // Here task goes in to wait state
break;
}
else{
//continue to download file
}
}
return null;
}
...
Using DDMS I found that task goes into wait State. Any suggestion to resolve this issue will be highly appreciated.
Thanks,
Yuvi
AsyncTask is a piece of work for PoolExecutor. When you execute your first task Executor creates first thread and executes your task on it. After task execution is finished the thread is not deleted. It starts waiting for a new task.
So it is normal to see AsyncTask thread in wait state.
P.S. It's better not to use AsyncTask for longtime operation. Use your own executor or thread.
P.P.S. AsyncTask uses single thread executor since 4.x. Be careful )
after you explicitly call asyncTask.cancel(true);, the onCancelled() method is called. Try overriding the following method:
#Override
protected void onCancelled() {
//what you want to do when the task was cancelled.
}
Say I am running
new CommentList().execute(url);
If I am in the doInBackground method and I catch a Null value and inside that null value exception I try running the same one again:
new CommentList().execute(url);
Will it stop running the first one?
Can I do this:
if (result == null) {
cancel(true);
}
#Override
protected void onCancelled() {
new CommentList().execute(commentlinkurl);
}
Basically I don't want the onPostExecute to run if it gets cancelled.
This is not a good idea. You should not be creating new task on a non-UI thread (from within doInBackground method).
From docs:
There are a few threading rules that must be
followed for this class to work properly:
The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
Edit based on comments:
You can however start the task again inside onPostExecute or onCancelled method. You can simply return some specific result to it from doInBackground or save your Throwable in the AsyncTask member variable to analyze it further:
protected void onPostExecute(Something something) {
if(something == null){
// safe to start new execute task here
}
// or
if(mException instanceof TemporaryIssueException){
// safe to start new execute task here
}
}