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.
Related
I want to create an autoCompleteTextview with the suggestion from the web-service. On text change I call the web service with the text entered.
public String searchpalace_Searchtext(String serchtext)
{
String resultString = "";
try {
String searchtext = URLEncoder.encode(String.valueOf(serchtext), "UTF-8");
HttpClient Clientloc = new DefaultHttpClient();
String URL = baseUrl + "places?name=" + searchtext;
HttpGet httpget = new HttpGet(URL);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
resultString = Clientloc.execute(httpget, responseHandler);
}
catch (Exception e) {
resultString = "";
}
return resultString;
}
This function is called from the asyncTask when reach character is entered or deleted. Now when the text is entered fast the I want to cancel the pending request when the new request is arrived. How can I cancel the previous request?
You can go through each queued task and call the cancel() method. Check if the task was cancelled using isCancelled(). Do not trigger async tasks for every change in the text box. You can introduce a small delay to avoid unnecessary creation of AsyncTask objects.
You can use Android volley network tool kid for cancel the HttpRequest,
If HttpClient.execute() can be interrupted, AsyncTask.cancel(true) will do it if you pass (true). The docs don't say if it's interruptable or not, experiment.
If it doesn't then you may need to investigate the toolkit suggested in another answer.
Anyway you can check isCancelled() and not apply the result. Probably not a huge overhead once the connection has been started.
Note that, depending on Android version, sometimes multiple AsyncTasks can run in parallel (donut - honecomb) and sometimes they only run one at a time and queue up (honeycomb onwards). You can change the thread executor to allow them to run in parallel, see the AsyncTask class docs, but this will affect the rest of your app too.
Also note you're not allowed to re-use an AsyncTask once it's been run.
I have a worker thread that runs in an infinite loop. If it's queue of http requests is empty it waits. As soon as a http request is added to the queue it gets notified and executes this http request. This works all fine but I have some questions on this:
I'm doing it something like this (shortened!):
mHttpClient = new DefaultHttpClient();
mHttpPost = new HttpPost(MyHttpClient.getAbsoluteUrl(url);
while (true)
{
// Check if the queue is empty, if so -> wait
StringEntity se = new StringEntity(queue.poll());
mHttpPost.setEntity(se);
HttpResponse response = mHttpClient.execute(mHttpPost);
}
The question is: is this the most efficient way to do it if the queue has like 100 items? Does the http connection remain open all the time or does it get connected again and again? And if it remains open, is it a good idea to leave it open all the time when the app is running, or should I close it until new items are added to the queue?
The second question is concerning the infinite loop. I need the thread to run all the time when the app is running but the still the infinite loop doesn't look nice. I know I could make something like: while(!cancelled) but I don't call a thread.cancel() method anyway because I mean there is no App.onDestroy() event where I could call thread.cancel(), right? How would you handle that? Because I'd actually want to save the queue to "disk" when the thread is killed by the system but how can this be done?
Sorry for the long text and my bad english
Fairly new to Android and created/tested my app using Android 2.3.5 (Gingerbread). I have multiple database connections I used HTTP Post (but did not use AsyncTask) and everything worked great. I then tested it on Android 4.0.3 (Ice Cream Sandwhich) and I'm not able to connect to the database, therefore my app does not work.
Wondering what do I need to consider to allow this working app to run on Ice Cream Sandwhich? I did move the database connection out of the UI Thread (but not AsyncTask) and it still does not connect.
Here is my class I created outside of my UI Thread:
public class InputsRecapGetTask {
public InputsRecapGetTask(InputsRecap activity,
ProgressDialog progressDialog) {
this.activity = activity;
this.progressDialog = progressDialog;
getDatabase();
}
public void getDatabase() {
// TODO Auto-generated method stub
progressDialog.show();
// create new default httpClient
HttpClient httpclient = new DefaultHttpClient();
// create new http post with url to php file as pararmenter
HttpPost httppost = new HttpPost(
"http://test.com/returnBBD.php");
// assign input text to strings
user = Login.userStatic;
Did you examine the logs? IIRC, Android 4 requires that http requests are not done from the main thread. There must be a message telling this.
On the other hand, please keep in mind that
if you turn the screen, the Activity that created the AsyncTask may
be removed from the screen (forever) and replaced by another
Activity; it (the 1st Activity) will receive the result, but will not show anything;
in Android 4, all AsyncTasks are by default serviced by a single
thread; this guarantees that responses arrive in the order the
requests are made, but also means that the 2nd request will start only after the
1st one finishes (or times out).
According to MVC, the data retrieval must be done by the model, not by the controller (Activity) whose lifetime is that of a View.
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.
I have some code below:
protected void testConnection(String url) {
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url);
ResponseHandler<String> responsehandler = new BasicResponseHandler();
try {
String connection = httpclient.execute(httpget, responsehandler);
Toast.makeText(getBaseContext(), R.string.connection_succeed, Toast.LENGTH_SHORT).show();
view_result.setText(connection);
} catch(IOException e) {
Toast.makeText(getBaseContext(), R.string.connection_failed, Toast.LENGTH_SHORT).show();
}
httpclient.getConnectionManager().shutdown();
}
and add a permission in Menifest:
<uses-permission android:name="android.permission.INTERNET"/>
But it goes an exception:
NetworkOnMainThreadException,
How can i do?
On ICS and later you cannot do network operations on the UI thread anymore. Instead you are forced to create a new thread and do your networking stuff there.
Possible tools are Android's AsyncTask and the normal Java Thread.
A good tutorial can be found here: Android Threads, Handlers and AsyncTask - Tutorial
Starting from API 11, you can not manipulate network (time-consuming) operations on main thread. Use AsyncTask or Thread to perform such operations.
You cant perform network operations in event thread, since android Api Level 11.
Instead you should do network operation in another thread than event thread, and use Handler or Asynctask to do so.
I you run your code in android 2.x and its lower version, i think this code will run perfectly. But if you run this in 3.x and it's upper version then you get an Exception. The problem is the you need to call the web service from your worker thread(AsyncTask<>) . You can not call the web service from the main thread.