Understanding asynctask

satya - Monday, July 26, 2010 2:59:07 PM

Android AsyncTask

Android AsyncTask

Search for: Android AsyncTask

satya - Monday, July 26, 2010 3:00:11 PM

start at the begining: the api link

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.

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

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?

Search for: 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

Search for: android progressbar progressdialog

satya - Tuesday, May 10, 2011 9:43:30 AM

progressdialog API

progressdialog API

satya - Tuesday, May 10, 2011 9:44:13 AM

ProgressBar

ProgressBar

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

Progress Bar API link

satya - Friday, May 13, 2011 1:38:41 PM

Source code for ProgressDialog.java

Source code for ProgressDialog.java

Search for: Source code for ProgressDialog.java

satya - Friday, May 13, 2011 1:39:25 PM

source at netmite for progressdialog.java

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

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

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

Here is a link

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?

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

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

On this page Android advises not to use a Progress dialog

satya - 8/16/2013 11:39:17 AM

Android advice on progress

Android advice on progress

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:53:36 AM

Here is a response of SOF

Here is a response of SOF

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

A deep dive into the Fragment life cycle callbacks

satya - 11/30/2013 11:33:59 AM

Some sample code to work Fragment Dialogs

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