I have recently refactored some of my networking code in my android app to use the Google recommended HTTPUrlConnection. Previously, I was using Apache's HTTPClient. I'm not sure if either of those things are relevant.
The other thing I have recently done to my networking code is use AsyncTask for the calls. Previously I was just doing work on the main thread (obviously bad) and so my application would appear to hang when fetching data. The thing is, since switching to AsyncTask, I have pretty regularly experienced timeout errors.
Why do I get this timeout error?
java.net.ConnectException: failed to connect to <url> (port 80): connect failed: ETIMEDOUT (connection timed out)
Here is my AsyncTask that makes the network call.
private class PostToPHP extends AsyncTask<PostToPHP, Void, String>
{
private String functionName;
private ArrayList<NameValuePair> postKeyValuePairs;
public PostToPHP(String function, ArrayList<NameValuePair> keyValuePairs)
{
functionName= function;
postKeyValuePairs = keyValuePairs;
}
#Override
protected void onPreExecute()
{
progressDialog = ProgressDialog.show(BaseActivity.getInstance(), "Loading", "Please wait...", true, false);
}
#Override
protected String doInBackground(PostToPHP... params)
{
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair(FUNCTION_NAME, functionName));
for (int i = 0; i < postKeyValuePairs.size(); i++) {
nameValuePairs.add(postKeyValuePairs.get(i));
}
try {
URL url = new URL("www.myurl");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setDoOutput(true);
urlConnection.setRequestProperty("Accept-Charset", iso-8859-1);
OutputStream os = urlConnection.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, iso-8859-1));
writer.write(getEncodedPostParameters(nameValuePairs, iso-8859-1));
writer.close();
os.close();
InputStream is = urlConnection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is, iso-8859-1));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
urlConnection.disconnect();
return sb.toString();
}
catch (UnknownHostException e) {
// handle it
return null;
}
catch (Exception e) {
// this is where I'm always getting a timeout exception
return null;
}
}
#Override
protected void onPostExecute(String result)
{
progressDialog.dismiss();
}
}
EDIT: I thought this only occurred during one particular network call but I've now experienced it at various places.
EDIT 2: Looking at this again I found this and I think that's more of my problem. This didn't exist before I implemented Android AsyncTask for the network calls. I think that AsyncTask is somehow screwing up with threading and causing the timeouts.
You could explicitly set the timeout for the HTTPUrlConnection:
urlConnection.setConnectionTimeout(aLongerTimeout)
I'm not very satisfied with this answer, but it seems to be working. I think there must be an issue with my code, or a bug in HTTPUrlConnection of some sort. I know Google said it had bugs in Froyo and lower, but I'm seeing oddities in 2.3.4 and 4.2 which I'm testing with. Essentially I replaced my code above with Apache's code and I'm not seeing the timeouts.
private static String post(ArrayList<NameValuePair> params){
HttpClient httpclient = new DefaultHttpClient();
HttpPost httpreq = new HttpPost("www.url.com");
httpreq.setEntity(new UrlEncodedFormEntity(params));
HttpResponse response = httpclient.execute(httpreq);
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is, NetworkConstants.HTTP_ACCEPTED_CHARSET), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
return sb.toString();
}
Related
I'm actually srugling with my application using HttpUrlConnection, I tried the simplest code found on the internet and still got a FatalShutDown in the logcat and I don't understand the problem.
Here is the code :
try {
URL url = new URL("http://www.android.com/");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
BufferedReader r = new BufferedReader(new InputStreamReader(in));
StringBuilder total = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
total.append(line).append('\n');
}
response_textview.setText(total.toString());
urlConnection.disconnect();
}
catch (MalformedURLException e){
response_textview.setText(e.getMessage());
}
catch (IOException e){
response_textview.setText(e.getMessage());
}
And I got this in the logcat :
Thanks
Wrap your code with Asynktask doInBackground() method.
You need to make request in new thread. Probably, your code (it is only try catch) is running on main thread. This operation is denied. Try to use e.g. Thread.class to make request in new thread.
You shouldn't perform network operation on main thread. Use AsyncTask.
1. Create AsyncTask object and move your code into doInBackground method as mentioned below:
AsyncTask task = new AsyncTask<Void,String,String>(){
#Override
protected String doInBackground(Void... params) {
// perform your network operation here and return response
try {
URL url = new URL("http://www.android.com/");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
BufferedReader r = new BufferedReader(new InputStreamReader(in));
StringBuilder total = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
total.append(line).append('\n');
}
urlConnection.disconnect();
}
catch (MalformedURLException e){
return e.getMessage();
}
catch (IOException e){
return e.getMessage();
}
return total.toString();
}
protected void onPostExecute(String response){
// response returned by doInBackGround() will be received
// by onPostExecute(String response)
response_textview.setText(response);
}
};
2. Execute task
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
Im trying to return a JSON string from this api:
https://market.mashape.com/pareshchouhan/trivia
however Java is throwing the error:
java.io.FileNotFoundException: https://pareshchouhan-trivia-v1.p.mashape.com/v1/getAllQuizQuestions?limit=10&page=1
On the line
br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
I have used similar code with other Rest APIs so i am a bit unsure why this is happenning.
static String jsonStr;
String data = "";
#Override
protected Void doInBackground(Void... params) {
BufferedReader br = null;
try {
URL url;
String urlStr = "https://pareshchouhan-trivia-v1.p.mashape.com/v1/getAllQuizQuestions?limit=10&page=1";
url = new URL(urlStr);
URLConnection connection = url.openConnection();
connection.setRequestProperty("X-Mashape-Key", "4OFryNEYTWmshe8GheSnmIVEj7gZp1kJf6cjsncjVhXj9WYACn");
connection.setRequestProperty("Accept", "application/json");
connection.setDoOutput(true);
OutputStreamWriter outputStreamWr = new OutputStreamWriter(connection.getOutputStream());
outputStreamWr.write(data);
outputStreamWr.flush();
br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder sb = new StringBuilder();
String line = null;
while((line = br.readLine())!=null) {
sb.append(line);
sb.append(System.getProperty("line.separator"));
}
jsonStr = sb.toString();
} catch (Exception e){
e.printStackTrace();
}
return null;
}
Any help would be greatly appreciated.
Regards.
Turns out I was trying to perform the wrong type of Request. This specific API did not support Get requests. Discovered this using https://www.hurl.it/
regardless, using the tutorial found here:
http://www.mkyong.com/java/how-to-send-http-request-getpost-in-java/
I was able to change the request type and pull the correct data.
Hope this helps.
My android servlet is designed to post request and receive responses with a tomcat servlet on an Apache Tomcat server. For debugging, I have set up the Servlet with identical POST and GET methods so I can try the functionalities and accessability via browsers.
To cut the long story short: When I deploy the app, I can easily access it from the AVD device browser via 10.0.2.2:8080/my_app?request=test and I get a result that's just fine. Same is true for access from my machine with localhost:8080/my_app?request=test.
But when I try it from my app, I always get a java.io.FileNotFoundException: http://10.0.2.2:8080/my_app.
Why?
What did I try so far: The app has internet permissions and they also work, for to get to the Servlet communication point, I have to go through a login procedure via PHP first, and it's on the same server and works normally.
My AsyncTaskconnecting to the servlet looks like this:
AsyncTask<Void,Void,String> getDBdata = new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
URL url = null;
try {
url = new URL("http://10.0.2.2:8080/my_app");
} catch (MalformedURLException e) {
e.printStackTrace();
}
String text;
text = null;
JsonArray js = null;
try {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("action", "getDBData");
connection.setDoInput(true);
connection.connect();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder builder = new StringBuilder();
String aux = "";
while ((aux = in.readLine()) != null) {
builder.append(aux);
}
text = builder.toString();
} catch (IOException e) {
e.printStackTrace();
}
return text;
Alright, of course I've been trying to send params in the header, and this led to BS. Rookie mistake!
bcody's answer from this question helped me a lot with debugging! Also, taking a look at the server protocol from the servlet might have led me to the error earlier.
This is the code that finally worked:
AsyncTask<Void,Void,String> getDBdata = new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
URL url = null;
try {
url = new URL(Constants.SERVER_URL + getDBdataURL);
} catch (MalformedURLException e) {
e.printStackTrace();
}
String text;
text = null;
try {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Accept-Charset", "UTF-8");
connection.setRequestProperty("User-Agent", "Mozilla/5.0 ( compatible ) ");
connection.setRequestProperty("Accept", "*/*");
connection.setChunkedStreamingMode(0);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setDoOutput(true);
connection.setRequestMethod("POST");
String request = "action=getDBdata";
PrintWriter pw = new PrintWriter(connection.getOutputStream());
pw.print(request);
pw.close();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder builder = new StringBuilder();
String aux = "";
while ((aux = in.readLine()) != null) {
builder.append(aux);
}
text = builder.toString();
} catch (IOException e) {
e.printStackTrace();
}
return text;
}
I have a problem with HttpGet that I've searched on stackoverflow and on other websites, I even followed some examples but nothing to do, it doesn't work.
This is my code:
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet("http://myurl.com/getit?token=" + _token);
HttpResponse response;
List<NameValuePair> params = new ArrayList<NameValuePair>();
String jsonString;
Gson gson;
Modules[] modulesList;
try {
response = client.execute(request);
//jsonString = EntityUtils.toString(response.getEntity());
//gson = new GsonBuilder().setPrettyPrinting().create();
//modulesList = gson.fromJson(jsonString, Modules[].class);
} catch (Exception e) {
System.out.println("FAIL: " + e.getMessage());
}
It always return a null pointer exception.
I've tried to display the URL, copy/paste in Chrome and the website does display my JSON.
The problem is quite clear in the first line of your stacktrace
/com.epitech.ferrei_j.epiandroid W/System.errīš android.os.NetworkOnMainThreadException 01-26
Post 2.3 Android you are not allowed to use the main UI thread to do tasks that can take a while to complete. Network IO is one of these.
You need to use an AsyncTask to execute the operation on its own thread.
See AsyncTask for examples on how to do this.
I usually write mine like this:
private String downloadUrl(String myurl) throws IOException {
InputStream is = null;
// Only display the first 500 characters of the retrieved
// web page content.
int len = 500;
try {
URL url = new URL(myurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(READTIMEOUT /* milliseconds */);
conn.setConnectTimeout(CONNECTTIMEOUT /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query
conn.connect();
int response = conn.getResponseCode();
//check to read content body if 400 error and above occurs.
if (response >= HttpStatus.SC_BAD_REQUEST)
is = conn.getErrorStream();
else
is = conn.getInputStream();
// Convert the InputStream into a string
String contentAsString = readIt(is, len);
return contentAsString;
// Makes sure that the InputStream is closed after the app is
// finished using it.
} finally {
if (is != null) {
is.close();
}
}
}
public String readIt(InputStream stream, int len) throws IOException,
UnsupportedEncodingException {
// Reader reader = null;
// reader = new InputStreamReader(stream, "UTF-8");
// char[] buffer = new char[stream.available()];
// reader.read(buffer);
// return new String(buffer);
final BufferedReader r = new BufferedReader(new InputStreamReader(
stream));
final StringBuilder total = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
total.append(line);
}
return total.toString();
}
So all you have to do afterwards is :
jsonString = downloadUrl( "http://myurl.com/getit?token=" + _token );
I developed android app and tested in Samsung tab 2.The code fetch the data from java server page which hosted in server.It works day before,but now it shows network time out exception during urlConnection.getInputStream() .I d't change anything in my code. pls help me to overcome the error.
try {
String tally_ipaddr="XXXXXXX";
URL url = new URL(tally_ipaddr+"/Iplogin.jsp");
urlConnection = (HttpURLConnection) url.openConnection();
String line = "";
InputStreamReader isr = new InputStreamReader(urlConnection.getInputStream());
BufferedReader reader = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null){
sb.append(line);
}
Toast.makeText(MyActivity.this, sb.toString(), Toast.LENGTH_LONG).show();
}
catch (Exception e) {
e.printStackTrace();
Toast.makeText(MyActivity.this, e.toString(), Toast.LENGTH_LONG).show();
}
class UrlFetch extends AsyncTask<Void,Void,Void>
{
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
try {
String tally_ipaddr="XXXXXXX";
URL url = new URL(tally_ipaddr+"/Iplogin.jsp");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000); // 5 seconds
conn.setRequestMethod("GET");
conn.connect();
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = rd.readLine()) != null) {
System.out.println(line);
}
conn.disconnect();
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
and call the asynctask like given below
new UrlFetch().execute();
Hope the above code will works for you
I notice the address ends with "Iplogin.jsp".
Make sure the server is accepting connections from the IP address of your device. I think the IP address of your device has changed and the server is no longer responding to requests from that device.
The fact that you can access the service from your desktop browser but NOT from the device browser is highly suspect.