I'm developing a program that sends some Logs to a database.
As logs, the main idea is to save as much information as it can, I want to avoid the part if the server where I store logs is down. What I'm trying to do is to make an http request and totally ignore server response, it doesn't matter if is online or offline. What I'm done so far is to set a timeout to my request but that doesn't resolve my problem. Here is my code:
public synchronized void LOG_sendERROR(String token, String channelnumber, String type)
{
HttpResponse response = null;
HttpParams httpParameters = new BasicHttpParams();
int timeout = 3000;
HttpConnectionParams.setConnectionTimeout(httpParameters,timeout);
int timeoutsocket = 5000;
HttpConnectionParams.setSoTimeout(httpParameters, timeoutsocket);
DefaultHttpClient httpclient = new DefaultHttpClient(httpParameters);
try
{
if (ep.getString("username", "").length() == 0)
return ;
String url = Server.Log_Server + "/LOG_CHANNEL_LOGS.aspx?params=1";
log.i("LOGS", url);
HttpGet c = new HttpGet(url);
response = httpclient.execute(c);
return ;
}
catch (Exception e)
{
e.printStackTrace();
try
{
if (response != null)
response.getEntity().consumeContent();
}
catch (Exception f)
{
}
return ;
}
}
If server is down my application stuck for 3 seconds. I want to send the logs, it doesn't matter for the client application to know whether the server saved the logs the client just send. How can I make a http request and ignore response?
After i tried many methods, the best way is to execute as a parallel task. In this way client wont ignore the response of the server but at least the application will be running normaly.
private Runnable LOG_CHANNEL_LOGS = new Runnable()
{
public void run()
{
new LOG_CHANNEL_LOGS().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
};
Related
When my activity loads, I am connecting to a web service. As and when I get the response from service, I again call then service and so on.
#Override
protected void onCreate(Bundle savedInstanceState) {
….
callWebMethod();
}
// Called on getting response
#Override
public void run(String value) {
….
callWebMethod();
}
This is how I am connecting to service
HttpGet request = new HttpGet(url + combinedParams);
HttpClient client = new DefaultHttpClient(httpParameters);
HttpResponse httpResponse;
httpResponse = client.execute(request);
responseCode = httpResponse.getStatusLine().getStatusCode();
message = httpResponse.getStatusLine().getReasonPhrase();
HttpEntity entity = httpResponse.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
response = convertStreamToString(instream);
response = StringUtils.remove(response, "\n");
response = StringUtils.remove(response, '"');
}
Is it possible that I connect to the service only once at the start, then the connection remains open and application keeps on reading data from service till connection is forcefully closed.
Please let me know if more code is required.
Update: I then tried with ClientConnectionManager but still connection is again and again initialising. Though it is getting data. What I want is that connection remains open, and keeps on reading data from service.
HttpParams httpParameters = new BasicHttpParams();
SharedPreferences preferences = context.getSharedPreferences(
"MyPreferences", Context.MODE_PRIVATE);
int timeoutConnection = Integer.parseInt(preferences.getString(
"timeout", "60")) * 1000;
HttpConnectionParams.setConnectionTimeout(httpParameters,
timeoutConnection);
HttpConnectionParams.setSoTimeout(httpParameters, 2000);
System.setProperty("http.keepAlive", "true");
HttpClient client = new DefaultHttpClient(httpParameters);
ClientConnectionManager mgr = client.getConnectionManager();
client = new DefaultHttpClient(new ThreadSafeClientConnManager(
client.getParams(), mgr.getSchemeRegistry()),
client.getParams());
while (true) {
HttpResponse httpResponse;
try {
httpResponse = client.execute(request);
responseCode = httpResponse.getStatusLine().getStatusCode();
message = httpResponse.getStatusLine().getReasonPhrase();
HttpEntity entity = httpResponse.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
response = convertStreamToString(instream);
response = StringUtils.remove(response, "\n");
response = StringUtils.remove(response, '"');
((Activity) context).runOnUiThread(new Runnable() {
public void run() {
callback.run(response); // This calls activity callback function.
}
});
// Closing the input stream will trigger connection release
// instream.close();
}
} catch (ConnectTimeoutException e) {
….
}
It sounds like what you really need is a socket connection (see here). A socket will stay connected and allow you to stream data back and forth with the socket server until you are finished.
you just need to close the InputStream you get from HttpResponse.getEntity().getContent() after you are done using/reading-it. This will officially indicate the end of your current request.
You can then proceed to execute another request, the same HttpClient connection will be used.
Add a close
InputStream instream = entity.getContent();
response = convertStreamToString(instream);
// close the InputSream
instream.close()
// you can now reuse the same `HttpClient` and execute another request
// using same connection
httpResponse = client.execute(request);
Is it possible that I connect to the service only once at the start,
then the connection remains open...
The web server has a role to play in this. If the server "ends" the HTTP response, there is no further communication going to happen on same HTTP call.
It is possible to keep an HTTP connection open, with help of server. In this case, server never really ends the response but keeps writing data to response stream after some time intervals, so client can keep listening.
The new replacement for the above technique is a duplex socket connection. Both client and server can send and receive messages over a socket. Again, both client and server have to support it properly, and necessary handling for connection drops etc has to be there.
There are android specific client implementations available like https://github.com/nkzawa/socket.io-client.java that take care of most of connection management for you.
I think you could try to use the AsyncTask class to try to keep your thread open and do what you want, like this:
public class ConnectToWebService extends AsyncTask<Void, Void, Boolean> {
#Override
protected Boolean doInBackground(Void... params) { ... }
#Override
protected void onPostExecute(final Boolean success) { ... }
#Override
protected void onCancelled() { ... }
}
Check the API documentation for more information ;)
I use to make two types of httpGet call. One for parsing JSON with Gson and one for getting the string, for small JSONs....
This is what I use for parsing with GSON:
static HttpGet getRequest;
static HttpResponse getResponse;
#SuppressLint("NewApi")
public static InputStream retrieveStream(String url) {
if (android.os.Build.VERSION.SDK_INT >= 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
int timeout = 30000;
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, timeout);
HttpConnectionParams.setSoTimeout(httpParameters, timeout);
DefaultHttpClient client = new DefaultHttpClient(httpParameters);
getRequest = new HttpGet(url);
try {
getResponse = client.execute(getRequest);
final int statusCode = getResponse.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w("ERROR", "Error " + statusCode + " for URL " + url);
return null;
}
HttpEntity getResponseEntity = getResponse.getEntity();
return getResponseEntity.getContent();
} catch (IOException e) {
getRequest.abort();
Log.w("ERROR", "Error for URL " + url, e);
} catch (Exception e) {
getRequest.abort();
Log.w("ERROR", "Error for URL " + url, e);
}
return null;
}
Yes, almost always, if there are some errors on JSON or there's no connection, it gives me null and I handle it.
Yes, almost always, if JSON is correct and I have connection, I can parse it successfully.
But few times, I think around 10 or 11 in one month, it doesn't do anything. It stops and doesn't continue (I let it for 20 minutes). It doesn't return null due to URL error, JSON error or TIMEOUT, it just stops. In that moment, my connection is stopped (no movements) but my connection works normally (because I receive messages from, for example WhatsApp).
So, if I open a ProgressDialog, it never closes because I can't handle a null or a successful InputStream, so I can't make the user know that, in the worst of the cases, he/she has to retry.
I'm making all this stuff asynchronously.
What am I doing bad?
Thanks in advance.
I'm experiencing some odd behavior in my HTTP requests. I have some users that are saying that this call isn't ever coming back (the spinner marking it's asynchronous call never goes away). I have seen this happen before, but I attributed it to the emulator going through Charles Proxy. I haven't yet seen it on actual phone until now.
I'm not sure what would cause this to happen, which is why I'm posting it here. Here's the call, using Jackson to deserialize the result into a Value Object. The two spots I saw the emulator freeze are httpclient.execute(httpGet); and getObjectMapper().readValue(jp, SyncVO.class);.
While debugging, stepping over the offending statement caused the debugger to never gain control back of stepping. Meanwhile, I see the request go out AND come back from the server through Charles. It's just that the app doesn't seem to get the response and just sits there.
So, here's the code. Thanks for any help!
public SyncVO sync(String userId, long lastUpdate, boolean includeFetch) throws IOException {
SyncVO result = null;
String url = BASE_URL + "users/" + userId + "/sync" + "?" + "fetch=" + includeFetch;
if (lastUpdate > 0) {
url += "&updatedSince=" + lastUpdate;
}
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
httpGet.setHeader("Accept", "application/json");
httpGet.setHeader("Accept-Encoding", "gzip");
httpGet.setHeader(AUTHORIZATION, BEARER + " " + mOAuthToken);
httpclient.getParams().setParameter(CoreProtocolPNames.USER_AGENT, USER_AGENT_STRING);
httpclient.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false);
HttpResponse response = httpclient.execute(httpGet);
if (isUnauthorized(response)) {
APPLICATION.needReauthentication();
return null;
}
if (response != null) {
InputStream stream = response.getEntity().getContent();
Header contentEncoding = response.getFirstHeader("Content-Encoding");
if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) {
stream = new GZIPInputStream(stream);
}
InputStreamReader inReader = new InputStreamReader(stream, "UTF-8");
JsonParser jp = mJsonFactory.createJsonParser(inReader);
result = getObjectMapper().readValue(jp, SyncVO.class);
}
return result;
}
private ObjectMapper getObjectMapper() {
return (new ObjectMapper()
.configure(Feature.AUTO_DETECT_FIELDS, true)
.configure(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true));
}
don't forget to consume entities content after each request.
HttpEntity entity = response.getEntity();
try {
if (entity != null)
entity.consumeContent();
} catch (IOException e) {
e.printStackTrace();
}
You should definitely use connection timeout and socket read and be prepared for the worst from the server. Network operations will never be 100% predictable and there is not much your client can do then so make sure you code optimally.
httpParameters = httpclient.getParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, 5000);
HttpConnectionParams.setSoTimeout(httpParameters, 10000);
You can also cancel a task with asyncTask.cancel(true);
The reason is because you have left stream open. As such, the response is left in limbo. This means your global variable httpClient is also left in limbo, and unable to get a new entity when it re-uses the client.
You should call close() after finishing with the stream.
stream.close();
Network calls take a while and will block the UI thread. Same with your jackson deserialization code. This stuff needs to be put on a separate thread. See AsyncTask for an easy way to do it.
I am trying to implement ping using HttpGet but behavior is random.
I am having following code which test the internet/server connectivity:
boolean result = false;
HttpGet request = new HttpGet("www.MyServer.com");
HttpParams httpParameters = new BasicHttpParams();
HttpClient httpClient = new DefaultHttpClient(httpParameters);
try
{
HttpConnectionParams.setConnectionTimeout(httpParameters, 6000);
HttpConnectionParams.setSoTimeout(httpParameters, 6000);
HttpResponse response = httpClient.execute(request);
int status = response.getStatusLine().getStatusCode();
if (status == HttpStatus.SC_OK)
{
result = true;
}
}
catch(Exception e)
{
e.printStackTrace();
result = false;
}
Log.d("App", "Ping Result:"+result);
Above code I am running in thread as it may take time.
When I run this test for first time then I get result as true, but then after behavior is random, some times it given me error 'host unreachable' and I get result as false.
I just want to test is server is reachable from the currently configured Android network.
Is there any reliable API to test the internet/server connectivity?
UPDATE:
In a Service i have following function which initiates the test.
void startTest()
{
ServerTestThread mServerTestThread = new ServerTestThread()
mServerTestThread.start();
}
class ServerTestThread extends Thread
{
boolean result = false;
public void run()
{
//HttpGet code
//Send Message TO GUI Thread with result.
}
}
Above startTest function is creating instance of the test thread and calling start function. when test is done I am sending message to main thread which contains the result.
Thanks.
There is no problem with your code. That means either:
Sometimes server is really unreachable
Connection is slow and it time outs before server is reached.
So test setting timeout to some larger value, such as 60000(60sec), and check again. If it works, then you know it was because of timeout.
EDIT
Also please make this change, maybe it gives us more info:
Log.d("App", "Status:" + status);
if (status == HttpStatus.SC_OK)
{
result = true;
}
EDIT2
class ServerTestThread extends Thread
{
public static boolean result = false;
public static HttpGet request = new HttpGet("www.MyServer.com");
public static HttpParams httpParameters = new BasicHttpParams();
public static HttpClient httpClient = new DefaultHttpClient(httpParameters);
boolean result = false;
public void run()
{
//HttpGet code
//Send Message TO GUI Thread with result.
}
}
As a bonus,
this will tell if you if you're connected to a network.
I need post data to server.
I use this code:
HttpClient client = new DefaultHttpClient();
try {
HttpPost httppost = new HttpPost(serverUrl);
StringEntity se = new StringEntity(data);
httppost.setEntity(se);
httppost.setHeader("Accept", "application/json");
httppost.setHeader("Content-type", "application/json");
// Execute HTTP Post Request
HttpResponse response = client.execute(httppost);
int statusCode = response.getStatusLine().getStatusCode();
Log.i(TVProgram.TAG, "ErrorHandler post status code: " + statusCode);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (client != null) {
client.getConnectionManager().shutdown();
}
}
But problem is that Android freeze on execute() method, application is blocked out and after some time Android tell me that application doesn't respond.
I tried to debug into SDK classes and it freeze in AbstractSessionInputBuffer class on the line 103 which is
l = this.instream.read(this.buffer, off, len);
I also tried it run the request in separated thread, but the same problem.
I tested it on Android 2.1 (emulator) and Android 2.2 real mobile device.
I also tried to set HTTP proxy and use Fiddler to check HTTP communication data are received by server and server also send correct answer and HTTP code 200. All seems to be ok.
What is wrong please?
UPDATE: When I use AndroidHttpClient which is part of Android 2.2 SDK it works great. But it is not in earlier version of Android. So I include it's source code in my app for now. But AndroidHttpClient use DefaultHTTPClient internally, so problem will be in configuration of DefaultHttpClient.
I am using a POST HTTP request successfully. Here is my code. I removed pieces using handler to display messages etc. and the handler itself.
The POST string is like "&NAME=value#NAME2=value2"...
protected class ConnectingThread implements Runnable
{
Message msg;
private Handler mExtHandler;
private String mData;
private String mUrl;
/**
* #param h (Handler) - a handler for messages from this thread
* #param data (String) - data to be send in HTTP request's POST
* #param url (String) - URL to which to connect
*/
ConnectingThread(Handler h, String data, String url) {
mExtHandler = h;
mData = data;
mUrl = url;
}
public void run() {
try {
// TODO use the handler to display txt info about connection
URL url = new URL(mUrl);
URLConnection conn = url.openConnection();
conn.setConnectTimeout(CONN_TIMEOUT_MILLIS);
conn.setDoOutput(true);
BufferedOutputStream wr = new BufferedOutputStream(conn.getOutputStream());
wr.write(mData.getBytes());
wr.flush();
wr.close();
String sReturn = null;
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
int length = conn.getContentLength();
char[] buffer = new char[length];
int read = rd.read(buffer);
if(read == length)
sReturn = new String(buffer);
rd.close();
buffer = null;
// TODO use the handler to use the response
} catch (Exception e) {
//....
}
// TODO use the handler to display txt info about connection ERROR
}
}
Isn't client.execute(httppost); synchronous ?
You probably need to put this in a thread, else it will freeze the UI.
Yes it is being freezed just becoz you haven't implemented this as Asynchronous process. Because while it makes web request, your UI will wait for the response and then it will be updated once the response is received.
So this should be implemented as Asynchronous process, and user should be notified (with progress bar or progress dialog) that there is something happening.
Now, Instead of implementing Runnable class, in android its preferrable and recommended to use AsyncTask, its also known as Painless Threading.
Do you background tasks inside the doInBackground() method.
Do your display type of operations inside onPostExecute() method, like updating listview with fetched data, display values inside TextViews....etc.
Display ProgressBar or ProgressDialog inside the onPreExecute() method.
Use AndroidHttpClient helped me in this situation.
But now complete AndroidHttpClient and DefaultHttpClient are obsolete in current version of Android so it is not important now.