0

I use many AsyncTask classes in my app. I always start them using:

if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
    asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
    asyncTask.execute();
}

Recently I got a RejectedExecutionException exception. I read about this and understand why this happens (exceeding the maximum number of tasks that thread pool executor can have in its queue).

But i didn't read anywhere about a way to check if thread pool executor has available slots so that I can avoid this. From what I tested the asyncTask.execute(); method does not have this limitation.

So I'm looking for something like this:

if(executorCanHandlerAnotherQueue()){ 
    if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
        asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    } else {
        asyncTask.execute();
    } 
}
else{
    asyncTask.execute();
}

Any ideas on how to implement this with backwards compatibility up to API 9?

Anonymous
  • 4,470
  • 3
  • 36
  • 67

1 Answers1

1

AsyncTask uses thread pool pattern, so it just provide a default number of thread. If you call execute(), the task will wait for a worker thread free to do.

To execute in a real parallel, you can call executeOnExecutor(). But it also is limited (maximum number of tasks = thread pool size + task queue size).

You can create a custom Executor to increase number of thread or task queue like this:

public static final Executor CUSTOM_THREAD_POOL_EXECUTOR
        = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

For running executor() function for Android lower than HONEYCOMB, you can use

AsyncTaskCompat.executeParallel(task, params);

from support v4 library.

You can find more details in this answer

UPDATE:

For checking executor available before execute, you can write a small function like that:

    boolean canExecutorAddAnotherQueue(ThreadPoolExecutor executor){
        int active = executor.getActiveCount();
        int corePoolSize = executor.getCorePoolSize();
        int poolSize = executor.getPoolSize();
        if (active < corePoolSize || active < poolSize) return true;
        int queueSize = executor.getQueue().size();
        if (queueSize < MAX_QUEUE_SIZE_YOU_DEFINED) return true;
        return false;
    }

But it maybe miss some cases that also accepted.

FINAL ANSWER:

So I found the best choice is using try catch:

        try {
            //execute asynctask
        } catch (RejectedExecutionException e){
            //Handle when has exception thrown
        }

Or using custom handler:

    public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)

You can write your own handler for handling cases which the task is rejected, and not throw the RejectedExecutionException anymore.

Community
  • 1
  • 1
Ken
  • 1,303
  • 13
  • 15
  • thank you for your responce but that wasn't the question. I allready know this. What I'm looking for is for a type of method like 'boolean canExecutorAddAnotherQueue()' which I can use to determine if I can add my asyncTask to the Executor thread pool – Anonymous May 26 '16 at 02:22
  • See my updated answer, you can use try catch or write a custom handler for your case. – Ken May 26 '16 at 03:07
  • The method you wrote seems more like it. try catch seems a poor approach...But I don't use a custom ThreadPoolExecutor. AsyncTask uses it's own. so the MAX_QUEUE_SIZE_YOU_DEFINED is the one that AsyncTask defines. Which from what I understand depends on the number of cores the devices has. Testing it on my device I saw that the exception is thrown when getQueueSize() is 128 but I don't know of a way to get that number using the API. – Anonymous May 26 '16 at 13:40
  • The pool size maybe 1, 5 or 128.. depends on the version of Android OS. You should define your own executor for having better management. Look at the code of ThreadPoolExecutor, it almost can not provide the value you want. – Ken May 27 '16 at 02:21