ASyncTasks blocking others - android

I've 2 ASyncTasks, one retrieves a value from an httpPost and the other update some elements of the UI (including an listview).
The problem is that since both ASyncTasks share the same background thread, if the network opperation start first and runs slow (due a bad network connectivity). The others background thread takes too much time making the app irresponsible.
Since both ASyncTasks are independient is pretty stupid one to make wait the other. It would be more logical asynctasks different classes use different threads, am I wrong?
Reading the ASyncTask doc. Talks about using executeOnExecutor(), but how can I solve that in a API level lower than 11?
Here goes a small example that reproduces the "problem"
new Task1().execute();
new Task2().execute();
With
public class Task1 extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
GLog.e("doInBackground start 1");
SystemClock.sleep(9000);
GLog.e("doInBackground end 1");
return null;
}
#Override
protected void onPreExecute() {
GLog.e("onPreExecute 1");
super.onPreExecute();
}
#Override
protected void onPostExecute(Void result) {
GLog.e("onPostExecute 1");
super.onPostExecute(result);
}
}
public class Task2 extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
GLog.e("onPreExecute 2");
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
GLog.e("doInBackground start 2");
SystemClock.sleep(9000);
GLog.e("doInBackground end 2");
return null;
}
#Override
protected void onPostExecute(Void result) {
GLog.e("onPostExecute 2");
super.onPostExecute(result);
}
}

This is how I handle this in my code:
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
new MyAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
new MyAsyncTask().execute();
}
And replace MyAsyncTask with yours Task1 and Task2 respectively. Basically change in AsyncTask appeared in Honeycomb (see Android SDK docs here in "Order of execution" section), so before that, you launch it as usual, for HC and up, use executeOnExecutor() if you do not like new behaviour (noone does, I think)

A slightly more general way to do this is to put two helper methods in a utility class like so:
class Utils {
#SuppressLint("NewApi")
public static <P, T extends AsyncTask<P, ?, ?>> void execute(T task, P... params) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
} else {
task.execute(params);
}
}
}
Then you can execute tasks with Utils.execute(mytask) or Utils.execute(mytask, params) and it will take care of executing them in parallel.

The problem is that every AsyncTask run in the same ThreadPoolExecutor which is coded into the API. This ThreadPoolExecutor can create a different number of WorkerThread depending on your Android version. I don't remember the number versions but the idea is that in older Android versions it was 1 WorkerThread. Then it was updated to 5 in later versions. And recently got moved back to 1 again. This is why your AsyncTasks are blocked. They run all on the same WorkerThread and thus they execute sequentially. Try using executeOnExecutor with THREAD_POOL_EXECUTOR to achieve true parallel execution. However you can use this only since API 11.

Related

Android: How multiple separate async tasks work?

In my Android program, I have to do 4 or 5 network calls. Each are independent, and each can run on their own.
public void backGroundTasks() {
new AsyncTasks<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
List<User> users = RetrofitAdapter.getClient().getUsersSync();
saveToDB(users);
} catch (RetrofitError error) {
error.printStackTrace();
}
return null;
}
}.execute();
new AsyncTasks<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
List<Media> contents = RetrofitAdapter.getClient().getContentsSync();
saveToDB(contents);
} catch (RetrofitError error) {
error.printStackTrace();
}
return null;
}
}.execute();
new AsyncTasks<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
Profile profile = RetrofitAdapter.getClient().getProfile();
saveToDB(profile);
} catch (RetrofitError error) {
error.printStackTrace();
}
return null;
}
}.execute();
new AsyncTasks<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
List<Message> messages = RetrofitAdapter.getClient().getMessages();
saveToDB(messages);
} catch (RetrofitError error) {
error.printStackTrace();
}
return null;
}
}.execute();
}
My questions are,
How this AsyncTask work ?
Will be executed in parallel ? or Will be invoked but the network requests will be queued ?
In some SO answers they have mentioned to do execute AsyncTasks with executeOnExecutor(). Will it help for this scenario ?
Note:
I use Retrofit library for making REST calls easier. Does it have anything with this problem ?
How this AsyncTask work ? Will be executed in parallel ?
Since honeycomb they will be executed serially, but if you will use executeOnExecutor then they will be executed in parallel.
or Will be invoked but the network requests will be queued ?
they will be queued, no network operation will start untill AsyncTask will get its turn.
Internally AsyncTasks use Executors. Your tasks only execute network operation, so you might switch to Executors. If you want to do your network operations serially, then you might also consider using IntentService.
This is answer by Arhimed. He explained it well.
AsyncTask uses a thread pool pattern for running the stuff from doInBackground(). The issue is initially (in early Android OS versions) the pool size was just 1, meaning no parallel computations for a bunch of AsyncTasks. But later they fixed that and now the size is 5, so at most 5 AsyncTasks can run simultaneously. Unfortunately I don't remember in what version exactly they changed that.
For more check his answer
Executors with AsyncTasks works like charm. It executes the network requests concurrently.
From the docs,
Since Honeycomb, invoking AsyncTask's executeOnExecutor() instead of execute() will execute tasks in parallel.
AsyncTask.THREAD_POOL_EXECUTOR
An Executor that can be used to execute tasks in parallel.

AsyncTask not call doInBackground methods

Here is my code:
new Loading.LoadTast(ctx) {
#Override
protected String doInBackground(Integer... params) {
Looper.prepare();
String msg=changePwd();
closeProgressDialog();
if(msg == null) {
SmartNgApplication.getInstance().exit();
} else {
BaseHelper.showToast(ctx, msg);
}
Looper.loop();
return null;
}
}.execute();
public abstract static class LoadTast extends AsyncTask<Integer, Integer, String> {
private ProgressDialog progressDialog;
private Context ctx;
public LoadTast(Context ctx) {
this.ctx=ctx;
}
protected abstract String doInBackground(Integer... params);
public void onPreExecute() {
super.onPreExecute();
progressDialog=ProgressDialog.show(ctx, "", "loading...", true, false);
}
public void onPostExecute(String result) {
super.onPostExecute(result);
progressDialog.dismiss();
BaseHelper.showToast(ctx, result);
}
}
Click the button to run the method. Clicking it 5 times AsyncTask.onPreExecute is called but not call doInBackground so the screen still show a dialog.
I think have something wrong for AsyncTask THREAD_POOL_EXECUTOR
You should not call any UI changing methods in doInBackground. Thats what onPostExecute is there for. Do only whats not allowed on the UI thread in doInBackground.
To check why doInBackground is not called, please try putting the implementation (from the anonymous inner class) into LoadTast just too see if it is called then.
I have implemented an AsyncWrapper by having subclasses call renamed onPostExecute and doInBackground. It should be possible to overwrite the wrapped Methods in an anonymous inner class like the one you are using in your example.
This is the short version. My real code involves some genral exception handling not only the call to the wrapped methods.
public abstract class AsyncTaskWrapper<Params, Progress, Result>
extends AsyncTask<Params, Progress, Result> {
#Override
final protected Result doInBackground(Params... params) {
return wrappedDoInBackground(params);
}
protected abstract Result wrappedDoInBackground(Params... params);
protected abstract void wrappedOnPostExecute(Result result);
final protected void onPostExecute(Result result) {
wrappedOnPostExecute(result);
}
}
As Todd Sjolander said in this thread ...
The multi-threading model changed between 2.3.5 and 4.0.4. AsyncTask
now defaults to having all subclasses in an application using the same
thread (i.e. only one AsyncTask can run at a time!). It's explained
here:
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.
With that in mind, it could be that another AsyncTask is running in
your app, thereby preventing this one from ever starting. That would
explain why it works fine on your 2.3.5 device, but not your 4.0.4
tablet.

How to work with AsyncTask and threads?

The goal:
Using Google App Engine server and Android client, I'm trying to put on the Google map at the Android client Users overlays. Every 30 seconds I'm polling the server and getting Vector that contains users and adding it to the map.
Current status:
I'm dong all that using in one new thread, So after running the app I got:
weird behaviors(delayed overlays, multiple overlays) and after that crushed with ConcurrentModificationException.
After reading a bit i figured out that I need to work with AsyncTask.
Correct me if I'm wrong,But I understand that everything done in the Activity at at onCreate is "running" in UIhread so I need to put the "Logic" (All the Network handling) in doInBackground and all the UI Handling like putting overlays on the map in onPostExecute.
My Question are:
1) In the current status I'm doing:
new Thread()
{
#Override
public void run()
{
super.run();
while(true)
{
SystemClock.sleep(30000);
Vector responseFromServer = getUsersVectorFromServer();
putNewOnlineUserOnTheMap();
}
}
}.start();
What is the right way to convert this To AsyncTask?
Do I poll the server still using new thread in the doInBackground or there is right way to do this?
2) Is there a specific list of what counts as UI to put in onPostExecute or any concepts list?
In my case I guess that in need to put putNewOnlineUserOnTheMap() in onPostExecute.
Thanks.
Something similar to the following:
class UpdateTask extends AsyncTask<Void, Vector, Void>{
#Override
protected Void doInBackground(Void... params) {
// this is running in a background thread.
while (!isCancelled()) {
SystemClock.sleep(30000);
Vector responseFromServer = getUsersVectorFromServer();
// send the result back to the UI thread
// onProgressUpdate will be called then
publishProgress(responseFromServer);
}
return null;
}
#Override
protected void onProgressUpdate(Vector... values) {
// this is executed on the UI thread where we can safely touch UI stuff
putNewOnlineUserOnTheMap(values[0]);
}
}
You can't use the result of the task since the task is finished then. But you can use the progress publishing mechanism to get periodic results. If you use it like that and do the modification on the UI thread you should not get ConcurrentModificationException because you do the modifications on the one thread that can safely modify the UI.
One thing to note here: create new instances of your Vector in the background thread and then use it to update the UI. But don't touch the same object afterwards in the backgroundthread. That way you don't need any synchronization since after the background thread sends it away it is only the UI thread that touches it. (and you could use a simple ArrayList instead of a Vector)
AsyncTask uses generics and varargs.The parameters that are passed to the asyntask are . TypeOfVariableArgumentsParameters is passed into the doInBackground(), ProgressParam is used for progress information and ResultParam must be returned from doInBackground() and is passed to onPostExecute() as parameter.
example:--
protected class ParsingTask extends AsyncTask> {
private ProgressDialog loadingDialog = new ProgressDialog(JsonParserActivity.this);
protected void onPreExecute() {
loadingDialog.setMessage("loading app store..");
loadingDialog.show();
}
#Override
protected ArrayList<Items> doInBackground( Context... params ) {
// do ur process here.
return result;
}
if (!this.isCancelled()) {
}
return result;
}
#Override
protected void onProgressUpdate(String... s) {
super.onProgressUpdate(s);
Toast.makeText(getApplicationContext(), s[0], Toast.LENGTH_SHORT).show();
}
#Override
protected void onPostExecute( ArrayList<Items> response ) {
//if u r dealing with list view and adapters set the adapter here at the onPostExecute()
loadingDialog.dismiss();
}
#Override
protected void onCancelled() {
super.onCancelled();
Toast.makeText(getApplicationContext(), "The operation was cancelled", 1).show();
}
}
You can use AsyncTask like below. Hope this will help you..
Class YourClass{
void YourClass(){
NetworkTask nT = new NetworkTasK();
nT.execute();
}
}
protected class NetworkTask extends AsyncTask<Void, String, Boolean>
{
#Override
protected Boolean doInBackground(Void... params)
{
try
{
String response;
while(keepreceiving)
{
response = in.readLine();//Prog Counter stops here until getting i/p.
if(response != null)
yourFunctionForResponse(response);
}
}
catch (Exception ex)
{
}
return null;
}
private void yourFunctionForResponse(String response){
//things to do....
}
}
You may also try runOnUiThread(Runnable action) along with this to implement your work.

Android SDK AsyncTask doInBackground not running (subclass)

As of 15/2/2012 I have yet to find a good explanation to nor a reason why this does not work. The closest to a solution is to use the traditional Thread approach, but then why include a class that does not (seem to) work in the Android SDK?
Evenin' SO!
I have an AsyncTask subclass:
// ParseListener had a callback which was called when an item was parsed in a
// RSS-xml, but as stated further down it is not used at all right now.
private class xmlAsync extends AsyncTask<String, RSSItem, Void> implements ParseListener
That is executed like this:
xmlAsync xmlThread = new xmlAsync();
xmlThread.execute("http://www.nothing.com");
Now this subclass has run into a little error. Previously it did some xml-parsing, but when I noticed that it's doInBackground() wasn't called I stripped it down, line by line, finally ending up with just this:
#Override
protected Void doInBackground(String... params)
{
Log.v(TAG, "doInBackground");
return null;
}
Which, for some reason, logged nothing. However, I added this:
#Override
protected void onPreExecute()
{
Log.v(TAG, "onPreExecute");
super.onPreExecute();
}
And that line is indeed logged when executing the thread. So somehow onPreExecute() is called but not doInBackground(). I have another AsyncTask running in the background at the same time which works just fine.
I'm currently running the app on an emulator, SDK Version 15, Eclipse, Mac OS X 10.7.2, close to the North Pole.
EDIT:
#Override
protected void onProgressUpdate(RSSItem... values) {
if(values[0] == null)
{
// activity function which merely creates a dialog
showInputError();
}
else
{
Log.v(TAG, "adding "+values[0].toString());
_tableManager.addRSSItem(values[0]);
}
super.onProgressUpdate(values);
}
_tableManager.addRSSItem() more or less adds a row to a SQLiteDatabase, initialized with the activity's context. publishProgress() is called by the Interface ParseListener's callback. However, since I don't even do anything except log.v in doInBackground() I first found this unnecessary to even bring up.
EDIT 2:
Alright, just to be perfectly clear, this is the other AsyncTask, executing in the same activity and working perfectly fine.
private class dbAsync extends AsyncTask<Void, RSSItem, Void>
{
Integer prevCount;
boolean run;
#Override
protected void onPreExecute() {
run = true;
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
run = true;
prevCount = 0;
while(run)
{
ArrayList<RSSItem> items = _tableManager.getAllItems();
if(items != null)
{
if(items.size() > prevCount)
{
Log.v("db Thread", "Found new item(s)!");
prevCount = items.size();
RSSItem[] itemsArray = new RSSItem[items.size()];
publishProgress(items.toArray(itemsArray));
}
}
SystemClock.sleep(5000);
}
return null;
}
#Override
protected void onProgressUpdate(RSSItem... values) {
ArrayList<RSSItem> list = new ArrayList<RSSItem>();
for(int i = 0; i < values.length; i++)
{
list.add(i, values[i]);
}
setItemsAndUpdateList(list);
super.onProgressUpdate(values);
}
#Override
protected void onCancelled() {
run = false;
super.onCancelled();
}
}
EDIT 3:
Sigh, sorry I'm bad at asking questions. But here is the initialization of the Tasks.
xmlAsync _xmlParseThread;
dbAsync _dbLookup;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
_dbLookup = new dbAsync();
_dbLookup.execute();
_xmlParseThread = new xmlAsync();
_xmlParseThread.execute("http://www.nothing.com", null);
}
You should checkout this answer: https://stackoverflow.com/a/10406894/347565 and the link to google groups it includes.
I had a similar problem as you, still unclear why it is not working, but I changed my code like this and problem is gone:
ASyncTask<Void,Void,Void> my_task = new ASyncTask<Void,Void,Void>() { ... };
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
my_task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
else
my_task.execute((Void[])null);
Matthieu's solution will work fine for most, but some can face problem; unless digging in many links provided here or from web, like Anders Göransson's explanation.
I am trying to summarize some other reads right here and quickly explain solution if executeOnExecutor is still working in single thread...
Behavior of AsyncTask().execute(); has changed through Android versions. Before Donut (Android:1.6 API:4) tasks were executed serially, from Donut to Gingerbread (Android:2.3 API:9) tasks executed paralleled; since Honeycomb (Android:3.0 API:11) execution was switched back to sequential; a new method AsyncTask().executeOnExecutor(Executor) however, was added for parallel execution.
In sequential processing all Async tasks run in a single thread and thus have to wait before the previous task ends. If you need to execute code immediately, you need tasks to be processed in parallel in separate threads.
With AsyncTask serial execution is not available between Donut and Honeycomb versions, while parallel execution is not available before Donut.
For parallel processing after Donut: Check the Build version and based on that use .execute() or .executeOnExecutor() method. Following code can help...
AsyncTask<Void,Void,Void> myTask = new AsyncTask<Void,Void,Void>() { ... }; // ... your AsyncTask code goes here
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB)
myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
myTask.execute();
NOTE: Function .executeOnExecutor() has checks if targetSdkVersion of project is less than or equal to HONEYCOMB_MR1 (Android:2.1 API:7) then it forces the executor to be THREAD_POOL_EXECUTOR (which runs Tasks sequentially in post Honeycomb).
If you have not defined a targetSdkVersion then minSdkVersion is automatically considered to be the targetSdkVersion.
Hence for running your AsyncTask in parallel on post Honeycomb you cannot leave targetSdkVersion empty.
You can do this by two ways:
Way 1:
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) // Above Api Level 13
{
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
else // Below Api Level 13
{
asyncTask.execute();
}
In case of way 1 not works for you try way 2.
Way 2:
int mCorePoolSize = 60;
int mMaximumPoolSize = 80;
int mKeepAliveTime = 10;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>(mMaximumPoolSize);
Executor mCustomThreadPoolExecutor = new ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize, mKeepAliveTime, TimeUnit.SECONDS, workQueue);
asyncTask.executeOnExecutor(mCustomThreadPoolExecutor);
Hope this will help you.
I had the same issue : can't a execute a second AsyncTask after i called "execute" on a first one : doInBackground is only called for the first one.
To answer why this happens check this answer (different behavior depending on the SDK)
However, for your case, this obstacle can be avoided using executeOnExecutor (available starting from 3.0 worked for me using 4.0.3 ) but beware of limitations of the Thread pool size and queuing.
Can you try something like this :
xmlAsync _xmlParseThread;
dbAsync _dbLookup;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
_dbLookup = new dbAsync();
_dbLookup.execute();
_xmlParseThread = new xmlAsync();
_xmlParseThread.executeOnExecutor(_dbLookup.THREAD_POOL_EXECUTOR
,"http://www.nothing.com", null);
}
For your update question : it is explained in the docs
Basically just to avoid all problems that may come from multithreading like intereference ....
One thing that I would like to know, and it might actually fix your issue, is where are you instantiating the instance of your class and calling the execute() method? If you read the documentation for AsyncTask, both of those operations need to take place on the main UI thread. If you are creating your object and calling execute from some other thread, then onPreExecute might fire, I'm not 100% certain here, but the background thread won't be created and executed.
If you are creating the instance of your AsyncTask from a background thread, or some other operation not taking place on the main UI thread, you could consider using the method:
Activity.runOnUiThread(Runnable)
You would need access to an instance of your running Activity to call that method, but it will allow you to run code on the UI thread from some other code that isn't running on the UI thread.
Hope that makes sense. Let me know if I can help more.
David
Android is Brutal! I can't believe this, what flakey implementation that changes from day to today. One day its a single thread, the next its 5 the other is 128.
Anyways here is a nearly drop in replacement for the stock AsyncTask. You can even call it AsyncTask if you wanted to, but to avoid confusion its called ThreadedAsyncTask. You need to call executeStart() instead of execute because execute() is final.
/**
* #author Kevin Kowalewski
*
*/
public abstract class ThreadedAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
public AsyncTask<Params, Progress, Result> executeStart(Params... params){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
return executePostHoneycomb(params);
}else{
return super.execute(params);
}
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
private AsyncTask<Params, Progress, Result> executePostHoneycomb(Params... params){
return super.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
}
}
I know this may be really late for the thread, but there is a reason why it won't work on later android emulators. When asynctask was introduced android only let you run one at a time, then sometime later, im not sure which version, they allowed you to run multiple asynctasks at once, this caused issues in alot of apps,and so in Honeycomb+ they reverted to only allowing one asynctask to run at a time. Unless you manually change the thread pool.
Hope that clears one or two things up for people.
i think its the sdk. i had the same problem, and after changing target sdk from 15 to 11, everything works perfectly.
with sdk15, even though the AsyncTask.Status is RUNNING, the doInBackground is never called. i do think it has something to do with the ui thread though.
Based on Matthieu's answer, below an helper class to execute your AsyncTask correctly depending of the SDK version in order to avoid to duplicate code in your application:
import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.os.Build;
public class AsyncTaskExecutor<Params, Progress, Result> {
#SuppressLint("NewApi")
public AsyncTask<Params, Progress, Result> execute(final AsyncTask<Params, Progress, Result> asyncTask, final Params... params){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
return asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
} else{
return asyncTask.execute(params);
}
}
}
Example of use:
public class MyTask extends AsyncTask<Void, Void, List<String>> {
...
final MyTask myTask = new MyTask();
new AsyncTaskExecutor<Void, Void, List<String>>().execute(myTask);

Android: Multiple with AsyncTask

I am learning Android via a book and would just like to confirm something.
When using AsyncTask according to the book it goes something like this:
main class
{
new AddStringTask().execute();
}
class AddStringTask extends AsyncTask<Void, String, Void> {
#Override
protected Void doInBackground(Void... unused) {
// Do something
SystemClock.sleep(333);
return(something);
}
#Override
protected void onProgressUpdate(String... item) {
// update something
}
}
which creates one background thread to do some stuff.
So if I want more threads, for example firing at different times (300, 500, 1000 milliseconds) then I need
to make even more sub classes... true?
Or is there some way to do multiple threads firing at different times using just this one subclass?
Thanks!
then I need to make even more sub classes... true?
Not true.
You can just execute the same AsyncTask again by creating a new AddStringTask() instance. This works since it'll be a new instance which differs from the other ones and each instance has its own thread. They are not interdependent.
However, the timer mechanism is something you have to implement yourself.
You could also use the same AsyncTask and publish diffrent progresses from the same thread. Let say :
protected Void doInBackground(Void... unused) {
...
System.sleep(500);
publishProgress(x);
System.sleep(500);
pulbishProgress(y);
}
and
protected void onProgressUpdate(String... progress) {
myLabel.setText(progress[0]);
}

Categories

Resources