90

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);
}
Community
  • 1
  • 1
SeruK
  • 987
  • 1
  • 8
  • 14
  • is it possible the activity is finishing before the task completes? – Paul Nikonowicz Feb 02 '12 at 20:40
  • Highly unlikely. In that case my other thread wouldn't be running right? And I only have one activity right now. – SeruK Feb 02 '12 at 20:58
  • 2
    My app has the same problem - doInBackground is either not called or called with a very long delay. Here is my limited observation: exactly the same code works flawlessly on an Android 2.3.3 smartphone and and an Android 2.3.3 emulator, but has this problem on an Android 4.0.3 tablet and a bunch of Android 4.x.x emulators. It is very tempting to conclude that this problem was introduced in newer versions of Android. – Hong Feb 21 '13 at 19:48
  • Sorry, but I forgot to mention this problem occurs only with the second AsyncTask of an Activity The first AsyncTask always works fine. – Hong Feb 21 '13 at 20:01
  • Hong, have you tried Matthieu's answer? I'm mostly out of the Android game ATM and have not worked with it for a while, so I can't tell if his answers actually works. If it doesn't for you, than maybe it was bad of me to accept his answer... – SeruK Feb 22 '13 at 11:06
  • I have exactly the same issue, i spent all my day on this but i could'nt find. When i noticed that logged in `doInBackground` is not shown, i was really surprised. I have too One activity and Two AsyncTask. The first task (file download) blocks the second (update UI with data from DB). – S.Thiongane Jan 21 '14 at 00:22

9 Answers9

160

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);
Community
  • 1
  • 1
Matthieu
  • 16,103
  • 10
  • 59
  • 86
  • I've been very bad at looking back at this post; I've long since moved away from the project. I'll just accept this as the answer since people seem to say it works. – SeruK Dec 20 '12 at 12:54
  • this worked for me just now but i wish i understood why. it was working fine with execute before then it stopped. one thing i'm doing is starting a new asynctask inside the onPostExecute of the same asynctask (i.e. i'm calling it recursively) maybe that's connected to the problem? – steveh Feb 20 '13 at 06:11
  • I think this should give you all the explanations you need: http://commonsware.com/blog/2012/04/20/asynctask-threading-regression-confirmed.html – Matthieu Feb 20 '13 at 17:22
  • 1
    @Matthieu : Sir, I really can't thank you enough!!! I had been beating my head on this problem for hours and your solution made everything work like a charm! Thank you so very much for the fantastic answer. I wish I could give more than one upvote!! – Swayam Apr 20 '13 at 19:38
  • anyway Do I need to review all AsyncTask I use in my code? It's a shame! :) – Seraphim's Jul 30 '13 at 15:58
  • This should be in the official documentation. There is no mention of it here http://developer.android.com/guide/components/processes-and-threads.html – 124697 Apr 04 '14 at 21:59
  • After applying this fix, which works, I realized that: by assuming the async task execute in parallel, I had added code that deadlocks if run serially. If you have one async task that is taking too long or waits for ever, it will deadlock other incoming async tasks. – jeremyvillalobos May 15 '14 at 02:03
  • @Walmart_Hobo your link is dead – joao2fast4u Mar 11 '15 at 16:08
  • 3
    @joao2fast4u http://web.archive.org/web/20131219080911/http://www.jayway.com/2012/11/28/is-androids-asynctask-executing-tasks-serially-or-concurrently – Andrey Mar 24 '15 at 19:25
  • Worked,but still has no clue why it does not execute at all. – zionpi Jul 15 '15 at 03:21
  • @zionpi, if it does not execute at all, then it's probably another problem. But then why do you say it worked? May be worth a separate question if you get stuck... – Matthieu Jul 15 '15 at 04:57
  • @Matthieu Your solution makes my custom asynctask execute as expected.Without your solution(considering sdk version),it sometimes executes ,sometimes donot. – zionpi Jul 15 '15 at 05:53
  • @zionpi, the changes make it possible for multiple ASyncTask to run in parallel. My understanding is that when you think it's not running the problem is that actually you already have another one running in the background and not finishing... – Matthieu Jul 16 '15 at 04:50
  • This worked for me. Strange thing is, a few days ago, it could run with just an execute() call. But suddenly it won't work anymore. – nomnom Dec 13 '15 at 16:25
108

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.

EMalik
  • 2,446
  • 1
  • 26
  • 13
  • 1
    Very good answer. While Matthieu's is not wrong I'm accepting this, since you add a bunch of important info. – SeruK Jul 31 '14 at 11:48
  • @Nashe Thanks a lot. It's really very helpful. I was fighting with this same issue for 3 days. Thanks again :) –  Aug 14 '14 at 08:03
  • 4
    Hey @Nashe, My problem is little awkward. Before today I was using the .execute() method on AsyncTask and the code was perfectly working. But today I got the problem - the control doesn't goes into the doInBackground() method. Though the solution you provide is working, I am puzzled how it was working before without the solution. I am using the same set of Devices before and now. – Ravi Sisodia Oct 29 '14 at 10:25
  • Why this should be this way? Why it does not work according to expectations? :( – Nikolay R Dec 18 '14 at 14:53
  • @RaviSisodia probably you added another Thread in your project... I had the same situation, yesterday all good today just one of the threads was not working... When I analysis in the big picture I understand that I have more jobs doing something and the Async wait for space to start... – Fernando Carvalho Jan 11 '16 at 15:14
  • You saved my day ! I was struggling about a weird behave because I'm using the AsyncTask to download an image inside the instantiateItem method from PagerAdapter. If I swipe very fast between the pages the "doInBackground" method stops being called. Your solution took this problem away, great ! – Leandro Silva Feb 27 '17 at 22:15
9

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.

Hiren Patel
  • 52,124
  • 21
  • 173
  • 151
  • super dude its working but next subsequent Async tasks which are using AsyncTask.THREAD_POOL_EXECUTOR are getting failed, so i need to change with CustomExecutor all over project i guess :( – kumar Mar 17 '16 at 07:59
  • @vinu, I suggest you to use common async task and common method for execute AsyncTask. Hope this will help you. – Hiren Patel Mar 17 '16 at 08:31
  • 2
    Hey this helped me a lot! Thanks! – Justin Ebby Nov 07 '17 at 06:15
6

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 ....

Community
  • 1
  • 1
code7amza
  • 181
  • 1
  • 8
5

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

David C. Sainte-Claire
  • 2,461
  • 1
  • 15
  • 12
  • adding to your answer this thread has an interesting answer http://stackoverflow.com/questions/4080808/asynctask-doinbackground-does-not-run. – manjusg Feb 03 '12 at 07:29
  • Thanks for the great answer! I upped this because I think that might be a common AsyncTask-beginner issue. Alas, it is not quite the right answer for this issue. Both classes are instantiated in an activity's onCreate() running on the main UI thread. I only have one activity in this project. – SeruK Feb 03 '12 at 07:33
  • @manjusg I've considered all along that it had something to do with AsyncTask being unstable, perhaps extra much so when several are run simultaneously. If so, why? – SeruK Feb 03 '12 at 07:37
  • I don't really know what policies SO has around posting rapidly three times in a row, but I found this in the other thread... http://foo.jasonhudgins.com/2010/05/limitations-of-asynctask.html "AsyncTask uses a static internal work queue with a hard-coded limit of 10 elements." This might prove something, but I just have two instances of AsyncTask-subclasses! I would really like to avoid using the normal threading methods since there will eventually be a lot of parsing done up in dere. – SeruK Feb 03 '12 at 07:45
2

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); 
    }
}
Kevin Parker
  • 16,975
  • 20
  • 76
  • 105
  • Wait, you're not saying some versions of Android restrict async ops to one thread are you? That would be incredibly silly. (I've been out of the Android game for a while. :) ) – SeruK Oct 03 '13 at 09:09
  • Yes, on Android 3.0+ if you don't use the AsyncTask.THREAD_POOL_EXECUTOR you only get a thread pool of one. Try it for your self, two AsyncTask's and just sleep in one's doInBackground. From the Android AsyncTask documentation: "Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution." – Kevin Parker Oct 04 '13 at 00:29
1

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.

0

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);
L. G.
  • 9,642
  • 7
  • 56
  • 78
0

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.

phobus
  • 31
  • 2
  • 2
  • I can neither deny or confirm as I don't really have the time right now to test it. All I can say is that I was using SDK 15, so it is very likely. – SeruK Feb 26 '12 at 12:54