Understanding asynctask
satya - Monday, July 26, 2010 2:59:07 PM
Android AsyncTask
Android AsyncTask
satya - Monday, July 26, 2010 3:00:11 PM
start at the begining: the api link
satya - Monday, July 26, 2010 3:04:58 PM
asynctask activity lifecycle
asynctask activity lifecycle
Search Google for: asynctask activity lifecycle
Search Android Developers Group for: asynctask activity lifecycle
Search Android Beginers Group for: asynctask activity lifecycle
Search Google Code for: asynctask activity lifecycle
Search Android Issues Database for: asynctask activity lifecycle
satya - Monday, July 26, 2010 3:16:43 PM
Very interesting thread that looks at orientation changes here
Very interesting thread that looks at orientation changes here
satya - Monday, May 09, 2011 1:13:18 PM
Brush up on generics
Asynctask uses generics. You may want to brush up on generics.
satya - Monday, May 09, 2011 1:15:28 PM
The link above also covers varying number of params...
The link above also covers varying number of params...
satya - Monday, May 09, 2011 1:33:21 PM
The nature of execution of asynctask
The nature of execution of asynctask
Quoting from the link
Executes the task with the specified parameters. The task returns itself (this) so that the caller can keep a reference to it. Note: this function schedules the task on a queue for a single background thread or pool of threads depending on the platform version. 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. After HONEYCOMB, it is planned to change this back to a single thread to avoid common application errors caused by parallel execution. If you truly want parallel execution, you can use the executeOnExecutor(Executor, Params...) version of this method with THREAD_POOL_EXECUTOR; however, see commentary there for warnings on its use.
satya - Monday, May 09, 2011 1:35:26 PM
You may want to read up on executors
satya - Monday, May 09, 2011 3:02:16 PM
why does publsihprogress takes multiple values?
why does publsihprogress takes multiple values?
satya - Monday, May 09, 2011 3:53:46 PM
Example of an async task
public class MyLongTask
extends AsyncTask<String,Integer,Integer>
{
IReportBack r;
public static String tag = "MyLongTask";
MyLongTask(IReportBack inr)
{
r = inr;
}
protected void onPreExecute()
{
//Runs on the main ui thread
Utils.logThreadSignature(this.tag);
}
protected void onProgressUpdate(Integer... progress)
{
//Runs on the main ui thread
Utils.logThreadSignature(this.tag);
//will be called multiple times
//triggered by onPostExecute
Integer i = progress[0];
r.reportBack(tag, "Progress:" + i.toString());
}
protected void onPostExecute(Integer result)
{
//Runs on the main ui thread
Utils.logThreadSignature(this.tag);
r.reportBack(tag, "onPostExecute result:" + result);
}
protected Integer doInBackground(String...strings)
{
//Runs on a worker thread
//May even be a pool if there are
//more tasks.
Utils.logThreadSignature(this.tag);
String s = strings[0];
for (int i=0;i<5;i++)
{
Utils.sleepForInSecs(10);
publishProgress(i);
}
return 1;
}
}
satya - Monday, May 09, 2011 4:01:06 PM
Key points
you have to extend from an async task
The asynctask class is genericised (or templatized). Read up on inheriting fromt templatized classes at one of the URLs above.
The key method you will need to override is doInBackGround. This takes an array of parameters (of your choosing) and respond on a background or worker thread.
This method then publishes the results, also using any array if needed. In the example we have just one value to report the progress. However this method returns a single value as a result.
Read up on thread allocation note above. Irrespctive of multiple threads or not, each task is executed on one thread. the thread pool comes into play if a client has multiple asynctasks that he/she has issued.
satya - Monday, May 09, 2011 4:01:49 PM
Here is how you call this task
MyLongTask mlt = new MyLongTask(this.mReportTo);
mlt.execute("Helloworld");
satya - Tuesday, May 10, 2011 9:38:41 AM
asynctask or spawn a thread: A discussion
asynctask or spawn a thread: A discussion
This is a link to the discussion on android developers group.
Here is my take from the discussion
I would say
1. Understand first how handler/looper/threrading works in android
2. Then you will realize that AsyncTask is just one pattern on top of
the above basics
3. Try to use AsyncTask if it can work for your problem as it simplifies the mechanics of threading/handlers. if not then go for the guts using handlers/threads
Coming to "thread pools" the latest documentation seem to suggest that after honeycomb the AsyncTask may roll back to a single thread implementation and have the programmer deal with multiple threads explicitly.
satya - Tuesday, May 10, 2011 9:40:28 AM
android progressbar progressdialog
android progressbar progressdialog
satya - Tuesday, May 10, 2011 10:24:30 AM
Here is a nice way to use a progress dialog in conjunction with asynctask
Step 1
//In your dervied asynctask hold on to a progressdialog
ProgressDialog pd = null;
Step 2
//You will i nit "pd" in preexecute
pd = ProgressDialog.show(ctx, "title", "In Progress...",true);
//The last "true" indicates that this
//is an indefinite dialog requiring an explicit cancel
//it does not have percentage indicator
//you will see a spinning wheel
Step 3
//In your post execute cancel it indicating success
pd.cancel();
satya - Tuesday, May 10, 2011 10:28:21 AM
Here is the program above rewritten for this
public class MyLongTask
extends AsyncTask<String,Integer,Integer>
{
IReportBack r;
Context ctx;
public static String tag = "MyLongTask";
ProgressDialog pd = null;
MyLongTask(IReportBack inr, Context inCtx)
{
r = inr;
ctx = inCtx;
}
protected void onPreExecute()
{
//Runs on the main ui thread
Utils.logThreadSignature(this.tag);
pd = ProgressDialog.show(ctx, "title", "In Progress...",true);
}
protected void onProgressUpdate(Integer... progress)
{
//Runs on the main ui thread
Utils.logThreadSignature(this.tag);
//will be called multiple times
//triggered by onPostExecute
Integer i = progress[0];
r.reportBack(tag, "Progress:" + i.toString());
}
protected void onPostExecute(Integer result)
{
//Runs on the main ui thread
Utils.logThreadSignature(this.tag);
r.reportBack(tag, "onPostExecute result:" + result);
pd.cancel();
}
protected Integer doInBackground(String...strings)
{
//Runs on a worker thread
//May even be a pool if there are
//more tasks.
Utils.logThreadSignature(this.tag);
String s = strings[0];
for (int i=0;i<5;i++)
{
Utils.sleepForInSecs(10);
publishProgress(i);
}
return 1;
}
}
satya - Wednesday, May 11, 2011 10:00:57 AM
API 11 introduced executeOnExecutor
API 11 introduced executeOnExecutor
Previously the asynctasks are executed using a threadpool. This is being rolled back to use a single thread by default. However a programmer can use this new method in API 11 to suggest the use of a multi threaded executor. see the api link above for details
satya - Thursday, May 12, 2011 1:37:21 PM
what you cannot do in doInBackground method
Because this method runs in a separate thread than the main thread you won't be able to make calls to views in your primary activity. If you do you will see an exception like CalledFromWrongThreadException
satya - Thursday, May 12, 2011 1:37:45 PM
CalledFromWrongThreadException
CalledFromWrongThreadException
Search Google for: CalledFromWrongThreadException
Search Android Developers Group for: CalledFromWrongThreadException
Search Android Beginers Group for: CalledFromWrongThreadException
Search Google Code for: CalledFromWrongThreadException
Search Android Issues Database for: CalledFromWrongThreadException
satya - Thursday, May 12, 2011 1:45:25 PM
You won't be able to do toast either from here
You will see the following error if you do a toast:
05-12 17:43:39.818: ERROR/AndroidRuntime(496): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
satya - Thursday, May 12, 2011 1:50:00 PM
Lesson: Somethings work only if they are done on the main thread
Lesson: Somethings work only if they are done on the main thread
satya - Thursday, May 12, 2011 2:08:15 PM
Here is an example running two asynctasks
public void test()
{
MyLongTask mlt = new MyLongTask(this.mReportTo,this.mContext,"Task1");
mlt.execute("String1","String2","String3");
MyLongTask mlt1 = new MyLongTask(this.mReportTo,this.mContext,"Task2");
mlt1.execute("String1","String2","String3");
}
In 2.3 of android these are automatically spawned off on two threads named AsyncTask #1 and AsyncTask #2.
I haven't tested this in API 11. In API 11 my understanding is that by default these will be executed sequentially unless an explicit method that allows thread pools.
satya - Friday, May 13, 2011 1:28:47 PM
To understand the behavior of progressdialog as a progressbar
To understand the behavior of progressdialog as a progressbar read the following link
satya - Friday, May 13, 2011 1:38:41 PM
Source code for ProgressDialog.java
Source code for ProgressDialog.java
satya - Friday, May 13, 2011 1:39:25 PM
source at netmite for progressdialog.java
satya - Friday, May 13, 2011 1:40:21 PM
Here is the show() function
public static ProgressDialog show(Context context, CharSequence title,
CharSequence message, boolean indeterminate,
boolean cancelable, OnCancelListener cancelListener) {
ProgressDialog dialog = new ProgressDialog(context);
dialog.setTitle(title);
dialog.setMessage(message);
dialog.setIndeterminate(indeterminate);
dialog.setCancelable(cancelable);
dialog.setOnCancelListener(cancelListener);
dialog.show();
return dialog;
}
satya - Friday, May 13, 2011 1:50:18 PM
It is too late to set the progressbar style to horizontal
it is clear from the code above. by default the style is spinner. one may have to explicitly do this otherwise.
satya - Friday, May 13, 2011 2:02:43 PM
Here is how you prepare the progress dialog
pd = new ProgressDialog(ctx);
pd.setTitle("title");
pd.setMessage("In Progress...");
pd.setCancelable(true);
pd.setIndeterminate(false);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setMax(5);
pd.show();
Notice I haven't used the built in show() instead copied the same code and set the right style for the progress dialog. As stated to understand some of the functions on the progresss dialog refer to the progressbar documentation.
satya - Friday, May 13, 2011 2:04:05 PM
Here is the long task above updated with this new type of progress dialog
extends AsyncTask<String,Integer,Integer>
{
IReportBack r;
Context ctx;
public String tag = null;
ProgressDialog pd = null;
MyLongTask1(IReportBack inr, Context inCtx, String inTag)
{
r = inr;
ctx = inCtx;
tag = inTag;
}
protected void onPreExecute()
{
//Runs on the main ui thread
Utils.logThreadSignature(this.tag);
//pd = ProgressDialog.show(ctx, "title", "In Progress...",false);
pd = new ProgressDialog(ctx);
pd.setTitle("title");
pd.setMessage("In Progress...");
pd.setCancelable(true);
pd.setIndeterminate(false);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setMax(5);
pd.show();
}
protected void onProgressUpdate(Integer... progress)
{
//Runs on the main ui thread
Utils.logThreadSignature(this.tag);
this.reportThreadSignature();
//will be called multiple times
//triggered by onPostExecute
Integer i = progress[0];
r.reportBack(tag, "Progress:" + i.toString());
pd.setProgress(i);
}
protected void onPostExecute(Integer result)
{
//Runs on the main ui thread
Utils.logThreadSignature(this.tag);
r.reportBack(tag, "onPostExecute result:" + result);
pd.cancel();
}
protected Integer doInBackground(String...strings)
{
//Runs on a worker thread
//May even be a pool if there are
//more tasks.
Utils.logThreadSignature(this.tag);
for(String s :strings)
{
Log.d(tag, "Processing:" + s);
//r.reportTransient(tag, "Processing:" + s);
}
for (int i=0;i<5;i++)
{
Utils.sleepForInSecs(2);
publishProgress(i);
}
return 1;
}
protected void reportThreadSignature()
{
String s = Utils.getThreadSignature();
r.reportBack(tag,s);
}
}
satya - Friday, May 13, 2011 2:08:53 PM
You can find here a couple of thread utility functions
satya - Saturday, May 14, 2011 9:13:43 AM
Here is a discusion on how to customize the progress view
satya - Saturday, May 14, 2011 9:14:01 AM
Here is a crux of that discussion
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:drawable/progress_circular_background" />
<item>
<shape android:shape="ring"
android:innerRadiusRatio="3.4"
android:thicknessRatio="6.0">
<gradient
android:useLevel="true"
android:type="sweep"
android:startColor="#ff000000"
android:endColor="#ffffffff" />
</shape>
</item>
<item>
<rotate
android:pivotX="50%" android:pivotY="50%"
android:fromDegrees="0" android:toDegrees="360"
android:drawable="@android:drawable/progress_particle" />
</item>
</layer-list>
satya - Saturday, May 14, 2011 9:39:02 AM
It may also behoove you to read up on configuration changes and weak references
satya - Saturday, May 14, 2011 11:04:47 AM
Responding to back
You can backout from a long running task by using cancellable on the progress dialog and issuing a cancel on the task.
This back will take you back to YOUR activity that started the task off. This is a pretty well defined interaction. You are still in the foreground.
satya - Saturday, May 14, 2011 11:13:39 AM
Responding to Home press
I don't think there is a good way to detect this. It is sure the activity stop is called. Most likely destroy won't be called. View state is maintained albeit invisible.
But samething could have happened in case of a rotation. In case of a rotation the view is destroyed and recreated on top.
either way a home press will not likely kill the process. So the asynctask continues to run. Ofcourse depending on the application you may chose to terminate the task in the "onstop". But if you do how do you prompt the user to restart it??
May be a better option is to let it run. If it takes real long to run perhaps this should not have been an activity but a service that can handle this type of long running operations.
But an operations worth a few minutes to 5 minutes you can let it run even on a home press and not react to it as a result. However you should realize that the view is invisible. You may want to know this in your long running task.
So the answer may be
Continue to run Realize that view is invisible
satya - Saturday, May 14, 2011 11:18:41 AM
Responding to rotation
In case of a rotate the process is still there but the activity that kicked off the asynctask is stopped and recreated. So asynctask is alive but the activity is gone and reborn.
Clearly stopping the asynctask is not a good thing.
So the things that need to be done are
Deal with view being invisible Deal with view being not there at all Locate the task Reestablish activity connection
satya - Saturday, May 14, 2011 11:21:01 AM
In other words...
you want the long running task to be aware of activty states and life time. May be have an interface called "ActivityAwareLongRunningTask" and then transfer the state information.
Due to activity rebirth you may want to use somekind of naming pattern for your tasks to establish activity hookup.
satya - Saturday, May 14, 2011 11:29:10 AM
when and how a process with asynctask is reclaimed?
satya - Saturday, May 14, 2011 12:23:33 PM
writing a (well: may be) behaved asyntask
have a progress dialog
enable cancel on back
stop asynctask on back
without onsave/restore:
stop asynctask
(ex: home)
with onsave/restore
keep asynctask running
rehook the activity
(ex: rotation)
satya - Friday, September 23, 2011 9:08:36 PM
Here is the progress dialog with out explcit progress
satya - Friday, September 23, 2011 9:09:47 PM
Here is a progress bar with explicit progress percentages
satya - 8/15/2013 4:20:31 PM
android progress dialog and configuration change
android progress dialog and configuration change
Search for: android progress dialog and configuration change
satya - 8/16/2013 11:00:15 AM
Does an android progress dialog gets recreated on configuration change automatically?
Does an android progress dialog gets recreated on configuration change automatically?
Search for: Does an android progress dialog gets recreated on configuration change automatically?
satya - 8/16/2013 11:00:41 AM
is there an equivalent fragment dialog for the older progress dialog in android?
is there an equivalent fragment dialog for the older progress dialog in android?
Search for: is there an equivalent fragment dialog for the older progress dialog in android?
satya - 8/16/2013 11:05:01 AM
Here are some API notes on a dialog fragment
Here are some API notes on a dialog fragment
This is to see what Android has to say about a possible replacement for the older progress dialog!
The ProgressDialog API does not indicate being deprecated directly.
satya - 8/16/2013 11:10:09 AM
Here are my notes on Fragment Dialogs from before
satya - 8/16/2013 11:15:26 AM
Can I use a progressdialog in a dialog fragment?
Can I use a progressdialog in a dialog fragment?
Search for: Can I use a progressdialog in a dialog fragment?
satya - 8/16/2013 11:38:46 AM
On this page Android advises not to use a Progress dialog but instead use a ProgressBar in the layout
satya - 8/17/2013 7:18:07 PM
it is best to have the activity or fragment deal with the progress updates
Don't do this in the task unless you have a framework that can handle multiple pointers that may not be there.
satya - 8/17/2013 7:18:50 PM
with that it is best that the asynctask holds a single weak reference to the activity/fragment
And delegate all UI related work to that parent activity/fragment.
satya - 10/13/2013 8:53:26 AM
Android ProgressDialog and DialogFragment and createDialog
Android ProgressDialog and DialogFragment and createDialog
Search for: Android ProgressDialog and DialogFragment and createDialog
satya - 10/13/2013 8:54:36 AM
The approach is ...
Return the non managed dialog object from a dialog fragment. In other words the dialog fragment is wrapping the non manager dialog.
satya - 10/13/2013 9:09:31 AM
So do you have a summary of a reasonable approach to an asynctask?
Writes are a different matter
For certain things an async task can get really hairy. Especially when you have a long running task that should not be interrupted due to the fact that you may be updating something in the database. In that case you may want to consider a long running service and the notification manager.
Reads are good and appropriate
If the task is such that it doesnt change the state of the data, mainly reads, then the approach to interact with a progress dialog will work. However there are nuances if you had read so far.
i will summarize here
You want your dialog to be a fragment dialog
You want your dialog to be a managed dialog so that rotation is taken care of by the activity. when I say managed, a dialog is best managed through a fragment. So use a fragment dialog as your progress dialog
You can make a fragment dialog from a progress dialog
You can wrap a regular non managed progress dialog in a dialog fragment to achieve a managed progress dialog.
You can use a progress bar as well
Also consider using a progress bar or its derived classes directly in the activity itself without a separate dialog. This is the recommended way as per the docs.
however sometimes it is nice for nothing else to be clicked on. So a dialog is practical as well
Reconnect to the asynctask through a non-ui fragment
There are two ways to reconnect to the running asynctask. You can use the older retain nonconfig instance method to get the asynctask object back in the activity restart and set its pointer
The recommended method is to use a non-ui fragment the very same way as a non-config instance. (You will set the retention method on the fragment to trigger this behavior for the fragment)
As a short cut you can also use the target fragment concept to communicate directly from the asynctask to the dialog fragment by passing the activity if your asynctask is a fragment and the dialog another fragment.
Lock Step...
Now the activity, the dialog, and the asynctask are in lock step! Unless ofcourse if you switch to home and the activity is invisible and the asynctask still running to its completion.
Of course the whole process may be removed from the memory if the focus is not this app, in which case the asynctask goes by by as well
In such cases a service is a better option.
satya - 11/30/2013 11:27:11 AM
You can also use a concept called ADOs instead of Retained Fragments
ADOs are activity dependent objects. The basic idea of ADOs is documented here. An implementation of ADOs and how to use them to solve the asynctask and progress dialog problem is is available here.
satya - 11/30/2013 11:28:02 AM
The test cases you must run to test your asynctask and progress dialog are here
The test cases you must run to test your asynctask and progress dialog are here
satya - 11/30/2013 11:29:12 AM
If you want to use ProgrressBars for the asynctask instead of a dialog this could help
If you want to use ProgrressBars for the asynctask instead of a dialog this could help
satya - 11/30/2013 11:30:48 AM
You must understands fragments really well to understand this topic. this might help
You must understands fragments really well to understand this topic. this might help
satya - 11/30/2013 11:32:50 AM
Activity life cycle is important to understand for this problem. this might help
Activity life cycle is important to understand for this problem. this might help
this URL gives you the callbacks of an activity and documents them as to when they are called and how to use that information
satya - 11/30/2013 11:33:29 AM
A deep dive into the Fragment life cycle callbacks
satya - 11/30/2013 11:33:59 AM
Some sample code to work Fragment Dialogs
satya - 11/30/2013 11:34:34 AM
A better pattern for constructing fragments: extending the newInstance idea with init methods
A better pattern for constructing fragments: extending the newInstance idea with init methods