I'm developing an app that requires multiple files being downloaded simultaneously. I am creating an AsyncTask with its own HttpClient for each file, but the next file only starts downloading after the previous one finished.
Might it be a server-side issue?
It is because AsyncTask management changed in Honeycomb . Previously if you started i.e. 3 AsyncTasks, these were running simultaneously. Since HC, if your targetSdk is set to 12 or higher, these are queued and executed one by one (see this discussion). To work that around start your AsyncTasks that way:
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
instead of:
task.execute(params);
If you target also older Androids, you need conditional code:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
} else {
task.execute(params);
}
or wrap it in a separate helper class:
public class Utils {
public static <P, T extends AsyncTask<P, ?, ?>> void executeAsyncTask(T task) {
executeAsyncTask(task, (P[]) null);
}
#SuppressLint("NewApi")
public static <P, T extends AsyncTask<P, ?, ?>> void executeAsyncTask(T task, P... params) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
} else {
task.execute(params);
}
}
}
and usage would be i.e.:
Utils.executeAsyncTask( new MyAsyncTask() );
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. Source
So depending on the version AsyncTask would not execute in parallel. For tasks like file download you should use thread pool using Executor
or you can use executeOnExecutor method..
It seems that you share an instance of HttpClient across your application and give your AsyncTasks their own methods. By the by, I'm fully aware that the link is for the older version, but the document doesn't seem to be updated for 4.x.
Related
I have an Android application that uses AsyncTasks to make get and post calls to send and retrieve data from server. All works fine but sometimes the async task takes a lot of time to execute and thus other async tasks have to wait (if more than 5 async tasks is there) so what will be the best alternative or how to increase the thread pool if it is safe to do so.
Asynctask are implemented behind the scene using threadpool, the default pool size for asynctasks is 1(so you can't run 2 asynctasks in parallel).
In newer versions of android the default Asynctask pool size is 5.
It's possible to change it but not recommended.
You can just create thread like in the sample I attached before:
Thread thread = new Thread() {
#Override
public void run() {
try {
//Do http request here
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
I have a Android app with a background service that sends info to an HTTP server. In the foreground I have a Activity that fetches info for the UI. Both use a doSending class that is inherited from AsyncTask to do the actual communication.
In this doSending class, I instantiate a DefaultHttpClient to run the communications. However, it seems like the "foreground" communication (triggered by the user) is blocked by the "background" communication (triggered by a timer).
private class doSending extends AsyncTask<Telegram, Integer, Long> {
[..]
#Override
protected Long doInBackground(Telegram... telegrams) {
[..]
HttpClient c = new DefaultHttpClient();
[..]
c.execute();
}
[..]
}
called like this:
Telegram t = new Telegram();
new doSending().execute(t);
Is it true that DefaultHttpClient can only have one connection at the time, app-wide? And if so, how do I make this multi-connected?
Are you sure it's the HttpClient and not the AsyncTask that can only have one running instance? If I recall correctly, the default threadpool for AsyncTask (unfortunately) has 1 thread associated with it which means only 1 active AsyncTask can run at any given time.
To fix, you can try this:
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
Have a look at this link for reference: http://commonsware.com/blog/2012/04/20/asynctask-threading-regression-confirmed.html
specially this sentence: If your android:targetSdkVersion is set to 13 or higher, and you are running on Android 4.x or higher, AsyncTask will use an Executor that executes only one task at a time.
I'm trying to run two AsyncTasks at the same time. However, only the first gets executed. And no data returned from second service. When refresh it second time I get data from service hoe to resolve the issue??
Here is my code
new MyClass().execute("Main");
> Class is
private class MyClass extends AsyncTask<Object, Void, String> {
> here i am using pre post and do in background methods
}
This allows for parallel execution on all android versions with API 4+ (Android 1.6+):
#TargetApi(Build.VERSION_CODES.HONEYCOMB) // API 11
void startMyTask(AsyncTask asyncTask) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
else
asyncTask.execute(params);
}
Since Webworkers is only implemented from Android 4.4 onwards, is it possible to have a wrapper in the application code that provides this functionality to the contained WebView?
An example on how to solve this would really help.
Thanks,
Rajath
I guess you are talking about running a javascript code block in the background, i.e. different thread. Had tried doing that using RhinoJS on Android. Tested on Android 2.2 and above
https://github.com/devthon/SilentJSAndroid
The main features are
Execute Javascript code without browser context
Execute Javascript code from a script file
Load other JS files in the same context
Execute a method in the background thread and return a result
Execute a Object.Method() call
Execute a prototype method call
Run long running script in the background after app is closed.
May not be a full fledged Web worker as such, since it doesn't have API to check the status in between. But that can be still added to the interface I believe.
If this is the direction you are looking for, I can explain more on how it is done.
How much of the Worker spec do you need to implement, and how flexible does the implementation need to be? You could probably get basic functionality up and running using a JavaScript interface[1] and spawning threads natively from Java. However this will get complex quite quickly.
Perhaps if you can describe what you are using workers for I might be able to offer a different/better suggestion.
[1] http://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object, java.lang.String)
--
Adding some pseudo code
In JavaScript spawn a Java worker thread:
var worker_id = window.Android.spawnWorker();
In JavaScript, run a task on that worker:
var task_id = window.Android.doAdditionOnWorker(2,2, worker_id);
Handle the result in JavaScript
function onReceiveResultForWorkerTask(task_id, result) {
alert("the answer was " + result);
}
Java side:
public int spawnWorker() {
HandlerThread worker = new HandlerThread();
worker.start();
Handler h = new Handler(worker.getLooper()) {
#Override
handleMessage(Message msg) {
switch(msg.what)
case ADD:
// calculate the answer and send back to JS via UI thread
// Unpack parameters and task id from Message
mWebView.post(new Runnable(
public void run() {
mWebView.loadUrl("javascript:onReceiveResultForWorkerTask(task_id, " + (a+b) +");");
}
)
}
};
mWorkerMap.put(mWorkerId++, h);
return mWorkerId;
}
public int doAdditionOnWorker(int a, int b, int worker_id) {
Handler h = mWorkerMap.get(worker_id);
Bundle b = new Bundle();
int task_id = mTaskId++;
// pack arguments and task_id into the bundle
h.postMessage(Message.obtain(h, ADD, b);
return task_id;
}
Don't forget to go through and tear down all the worker threads that you spawn when the app doesn't need them anymore. Depending on how many workers you need you might also prefer to use a thread pool rather than creating new threads every time.
I have a bit of an issue with some Async tasks that are running in my android application. Due to the fact I am using some network IO, it can sometime's take longer than expected and block other async tasks running.
I need to keep my target and min sdk versions as they are but they are targeting targetSdkVersion="15" with a minSdkVersion="8". I require it so that when an Async task is called, I can check the devices SDK and if is greater than 11 it can call executeOnExecutor() as opposed to just execute to allow the device to run these in parallel and prevent this blocking operation.
Although I have a target SDK of 15, the device I am using has an SDK of 17.
However when calling:
MyAsyncTask(this).executeOnExecutor();
I get an error "The method executeOnExecutor() is undefined for the type" and the only option available to me is:
MyAsyncTask(this).execute();
MyAsyncTask is a class object that extends AsyncTask and overloads the standard methods onPreExecute, doInBackground, onProgressUpdate & onPostExecute.
I tried following some of the advice listed here... http://steveliles.github.io/android_s_asynctask.html
Set your build target to API Level 11 or higher. Note that "build target" != "target SDK" (android:targetSdkVersion). "Build target" is set in Project > Properties > Android on Eclipse, or project.properties for command-line builds.
For conditional use of executeOnExecutor(), another approach is to use a separate helper method:
#TargetApi(11)
static public <T> void executeAsyncTask(AsyncTask<T, ?, ?> task,
T... params) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
}
else {
task.execute(params);
}
}
You would then use this method to kick off your tasks:
executeAsyncTask(new MyTask(), param1, param2);
(for however many parameters you wanted to pass to execute())