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.
Related
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 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
I am developing an Android app for connecting to Tridion 2011 SP1 Core Service.
So far I have created Android WS Stubs from the core service wsdl using wsclient.
Imported those stubs, which allow access to all the core service methods.
I can now authenticate to Tridion via the Android application but as soon as I try to perform even the most basic of web service calls, such as getApiVersion(), I get the error:
ReflectionHelper*java.lang.NoSuchFieldException: GetApiVersionResult.
I was wondering has anyone else managed to create a java android app that communicates with the Core Service?
Interestingly enough, if I run the code as a java application, using wsimport stubs everything works a treat.
Any help appreciated. For reference here is a code snippet:
To connect to Tridion:
class TridionConnect extends AsyncTask<String, Integer, String> {
// Called to initiate the background activity
#Override
protected String doInBackground(String... statuses) {
try {
Authenticator.setDefault(new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("username", "password".toCharArray());
}
});
url = new URL("http://tridion-server/webservices/CoreService2011.svc?wsdl");
System.out.println(String.format("Get Service"));
service = new CoreService2011();
System.out.println(String.format("Get Client"));
client = service.getBasicHttp();
return "Authenticated To Tridion";
} catch (Exception e) {
Log.e("Authentication failure", e.toString());
e.printStackTrace();
return "Failed to authenticate";
}
}
// Called when there's a status to be updated
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// Not used in this case
}
// Called once the background activity has completed
#Override
protected void onPostExecute(String result) { //
Toast.makeText(FullscreenActivity.this, result, Toast.LENGTH_LONG).show();
area.setText("Authenticated to Tridion OK");
}
}
To get the ApiVersion
client.getApiVersion();
UserData currentUser = client.getCurrentUser();
System.out.println(String.format("'%s' %s", currentUser.getTitle(), currentUser.getId()));
Frank,
It is not possible for a couple of reasons.
If you use wsimport to create the coreservice proxy it will use the javax library, which exists in the JRE. However Dalvik implements only a subset of the javax library which means this approach is impossible in the Android environment.
I then looked at Ksoap2 tools for creating the proxy. This seemed to work OK, in as much as it did create a proxy, however it did not match the coreservice so I was unable to authenticate. I didn't get any further with this approach beyond examining the JRE proxy v Ksoap2 proxy. They were quite different.
At this point I took a step back, had a cup of tea and re-engineered the approach.
I created a c# REST service to sit between the android app and the core service.
This approach seemed a bit complex, but it offers lots of advantages. Lots of the spade work can be done in the REST service, which will be much quicker than similar code on a tablet or phone.
Secondly the REST service sits on the same server as the CMS/CoreService so the comms is quicker and you can make the REST requests from the android app much lighter.
I have got the application to the point where you can authenticate to Tridion, select a publication, and components that is then rendered in a dynamic layout ready for update/save/publish.
The one big downside of this approach is that the REST service 'should' be stateless so superficially you have to authenticate to the coreservice for every request. Of course I don't do that, but you have to come up with some alternative approach Oauth, shared secret etc.
In initial tests this approach has seemed to be fairly slick on an android device.
I'm trying to post data to URL by using Android App.
URL:
parameters:
"name" and "message"
I use the following code but it doesn't work:
public void onClick(View v) {
// Create a new HttpClient and Post Header
// Create a new HttpClient and Post Header
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://comparch2011.appspot.com/");
try {
// Add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("name", "DEV"));
nameValuePairs.add(new BasicNameValuePair("message", "AndDev is Cool!"));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
} catch (IOException e) {
// TODO Auto-generated catch block
}
}
-first thing first : you should use adb logcat. It will give you real time logs of your phone on your computers, it is incredibly useful to know what is going on.
-I suspect that you are making these calls in an Activity and in this case the app is simply crashing because of that : their is a safeguard to prevent you from doing that. It raises errors 'network on main thread' when necessary (like here).
The problem is that Activities are ran on the main thread, the one that is also used for the UI. so when you make such a network call, all the UI is blocked until the function has returned (and since it is waiting for the website to respond it can take a couple of seconds, which is very bad for the usability of your app).
The solution is to use an AsyncTask . It is an easy to use class that will allow you to make asynchronous calls (ie calls that don't block the UI).
As you can see in your LogCat, the error is a NetworkOnMainThreadException.
Which Android states here http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html as:
NetworkOnMainThreadException:
The exception that is thrown when an application attempts to perform a
networking operation on its main thread.
This is only thrown for applications targeting the Honeycomb SDK or higher. Applications targeting earlier SDK versions are allowed to
do networking on their main event loop threads, but it's heavily
discouraged.
So take a look at http://developer.android.com/reference/android/os/AsyncTask.html instead, and be aware that the getResponse not should be called on the UI thread.
Alternatively you can probably just change the target or change the strictpolicy as follows, but I would no suggest doing so...
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
You shouldn't perform Network activities on the main thread. Because it doesn't allow the user to respond to the view when the network action is being performed.
Use an Asynctask, and it will work.
http://developer.android.com/reference/android/os/AsyncTask.html
Nithin