I have a class called LoadEncryptedImage and that is derived from AsyncTask.
I used the below code to execute the async tasks in parallel,
LoadEncryptedImage loadEncryptedImage = new LoadEncryptedImage(mContext, eventMember.MemberPhotoURL,
viewHolder.imgUser);
loadEncryptedImage.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
It works properly, but it throws RejectedExecutionException if the tasks exceeds the limit of the ThreadPool. I want to set DiscardPolicy on ThreadPool to discard the issue silently. But how we can do this on a Threadpool created using ExecuteOnExecutor method.
But how we can do this on a Threadpool created using ExecuteOnExecutor method.
That is not a good idea. Do not change the characteristics of a thread pool that you did not create, as other things that depend upon that thread pool may not appreciate the changes that you make.
Instead, create your own ThreadPoolExecutor, with your desired characteristics, and pass that into executeOnExecutor().
Related
I have been reading about Executor in Android documentations. If I understood it correctly, it is used for multiple thread management and it does some of the work for you like spawning new threads when needed. Or you may choose to manage stuff yourself.
In the example below, a group of executors are used instead of one. So it is something like a pool of pool of threads (?).
/**
* Global executor pools for the whole application.
*
* Grouping tasks like this avoids the effects of task starvation (e.g. disk
reads don't wait behind
* webservice requests).
*/
#Singleton
open class AppExecutors(
private val diskIO: Executor,
private val networkIO: Executor,
private val mainThread: Executor
) {
#Inject
constructor() : this(
Executors.newSingleThreadExecutor(),
Executors.newFixedThreadPool(3),
MainThreadExecutor()
)
fun diskIO(): Executor {
return diskIO
}
fun networkIO(): Executor {
return networkIO
}
fun mainThread(): Executor {
return mainThread
}
private class MainThreadExecutor : Executor {
private val mainThreadHandler = Handler(Looper.getMainLooper())
override fun execute(command: Runnable) {
mainThreadHandler.post(command)
}
}
}
Why would one choose to use a group of executors? What do you achieve with it which you can't with just one executor?
That's just structuring and assigning the right executor for the right jobs they might execute:
It's nicely put in a single class for easy reuse.
Three types of executors are employed, each for a specific type of task it could run. Remember that executors have threads to execute jobs or Runnables and each thread the executor creates can run one job at a time:
diskIO is (from the constrcutor) a Executors.newSingleThreadExecutor() since the tasks are best queued and executed one at a time to reduce write and read locks or race conditions for example. Hence a SingleThreadExecutor would run only one task at a time no matter how many are queued to ensure that design. Being a single thread could also mean that it's being used for writing app logs to a file for example which allows for the logs to be written in the proper order as being submitted to the executor. Hence single thread is best at maintaining output as in the order of jobs queued.
networkIO is a Executors.newFixedThreadPool(3) since the tasks are usually network related like connecting to a server on the internet and performing requests or getting data. These tasks usually make the user wait (could be between seconds to minutes) and need to be executed in parallel and fast to make the wait shorter in case many requests need be performed together. Hence the reason there are 3 threads employed with this executor is to assign the tasks among them and execute together. Order of jobs is not a concern here since jobs take different amount of time to execute but what matters the most is that they're running in parallel.
mainThread is a MainThreadExecutor() which in an Android app handles the UI and drawing it. The UI should function smoothly and not lag and hence the reason to use the above two executors is to let any heavy task (like writing a file or performing requests) to run in the background or separately from the mainThread of the app. This executor keeps performing tasks even if the app didn't submit any to it. The tasks it keeps performing is drawing the UI continuously on the screen which constantly repeats. Tasks executed by the mainThread need to lightweight and fast (time they take are in the order of milliseconds), and so any task that slows it down will be noticed as the UI will lag or glitch with it because the mainThread is busy finishing that task instead of drawing and updating the UI. The mainThread here simply uses a Handler which is part of the Android SDK/architecture, is of a single thread type and behaves like an executor (with some differences) that queues tasks to create/update the UI. Only a Handler can perform UI tasks, none of the other executors can.
For example there is an AsyncTask of a String... parameters , if I make a call like this :
AsyncTask<String, Void, Void> someTask = new myTask(myActivity.this);
someTask.execute(string1 , string2 , string3);
What is the internal order of execution of the doInBackground inside this task : does it treat string1 first then string2 and so on sequencely as they are provided when called , or does it treat the parameters randomly ?
First thing, parameters are not passed randomly. This answer will explain you more about parameters. Also check image from this answer. I am adding same image here for your understanding.
It may be serial on one thread or parallel, it actually depends upon which version of Android OS your app is running. For most of the case it would be serial on one background thread.
This is what google document says :-
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. Starting HONEYCOMB, tasks are back to being executed on 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.
This method must be invoked on the UI thread.
Check this link execute (Params... params) it will help you.
Hope it helps,
Thanks.
String... is a "vararg", which in this example converts all individual parameters into a String[], where the entries to the array are in the order they got passed into the method.
So using your example, (String[]) param[0] == string1, param[1] == string2, param[2] == string3 and so forth. This is for the ordering of param entries, as to how each entry in param is used, it depends entirely on your code.
I want to run a number of AsyncTask's on AsyncTask.THREAD_POOL_EXECUTOR.
I am using the following code.
Tasks[i].executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
taskParams);
After certain number of threads was sent to the executor, it no longer accepts new AsyncTasks. (I do not see any errors, but doInBackGroundMethod is not started for some reason).
I suspect this happens because it's pool is full.
Is there any way to reset the executor?
I want to completely terminate all the tasks so that it will start to accept new tasks again and process them immediately.
I tried to terminate the Tasks using their cancel method, but it didn't help.
Are your tasks finishing? Are you handling the apropriate exceptions? How many tasks are you creating?
Keep in mind that AsyncTask.THREAD_POOL_EXECUTOR (at least in API 17; this doc page has a bunch of useful details), is set up with
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
Where CORE_POOL_SIZE is 5 and MAXIMUM_POOL_SIZE is 128.
The sPoolWorkQueue with
private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(10);
This means that the queue has a maximum capacity of 10 items.
The THREAD_POOL_EXECUTOR keeps at least 5 threads alive. As tasks are added, they are added to the queue. When the queue fills, then new threads will be spawned, up to 128 (there are other limitations tho).
When this happens (128 threads, the max, are running and the queue is full) then any new tasks will be rejected, and handled with the default handler (since it's not being set explicitly, is AbortPolicy), which throws a RejectedExecutionException.
Make sure that you're not just catching and not handling such exceptions.
One way to deal with this is to create your own ExecutorService (even if it's just your instance of ThreadPoolExecutor with different parameters) and configure the parameters that fit your situation best. Parameters like the queue (you can control the amount of items it can hold, or if it's unbounded, etc) or how to handle rejected tasks.
I can see two reasons to having cancelled AsyncTasks still running:
Either you don't call cancel with mayInterruptIfRunning set to true
Either you do call AsyncTask.cancel(true) but the InterruptedException is miss-handled by the executed code: Make sure your code (and the possible subsequent calls to libraries) don't obfuscate/silence InterruptedExceptions by a try/catch on InterruptedExceptions or even on Exception.
When executing AysncTask, The following api I am using
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"nameofpool");
Is it possible that somehow I can set only 2 threads limit in this pool.
The AsyncTask.THREAD_POOL_EXECUTOR is a special pool that is created for you and administrated by Android.
You can, however, create your own Executor, typically using :
Executor myExecutor = Executors.newFixedThreadPool(2);
which you can use in your AsyncTask :
executeOnExecutor(myExecutor, params);
Nota: please note that your param "nameofpool" is actually the parameter to the doInBackground method on your AsyncTask, and is not related to the Thread pool management.
You can provide your own executor:
executeOnExecutor(Executors.newFixedThreadPool(2), "nameofpool");
I would like to send more than one request to server parallelly using AsyncTask in android
so how can i do that ?
I have seen code like
myAsync.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params)
but it is not running parallelly instead it is running serially.
please help me out.
Hey the executeonExecutor should work perfectly.
You will need to use a thread pool Executor to execute Asynctask . Default implementation uses a serial executor running on a single thread
So create a ThreadPoolExeecutor and then use
Asynctask's executeonExecutor instead of just execute method
There has been a change in AsyncTask from Honeycomb release. Older versions had a Thread pool of 10 threads, so you could run 10 tasks in parallel. But for Honeycomb and up, default is a serial executor, which executes tasks one by one. But you can pass a ThreadPoolExecutor for execution:
if (Build.VERSION.SDK_INT >= 11) {
//--post GB use serial executor by default --
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
//--GB uses ThreadPoolExecutor by default--
task.execute();
}
Create new instance of the async task and execute, then it will execute parallelly
simply... use
new YourAssynctask().execute();
this will indeed call your Assyntask's OnpreExecute() method.