Android Java HttpUrlConnection freezing - java

I suspect I'm running into some issues borne out of threading in my simple Android app.
I have a Activity which does the following:
runs a dialog on main thread
spins a background thread and hits a PHP script for retreiving data using DefaultHttpClient and close this connection. This successfully returns a URL to a picture on the internet
open HttpUrlConnection called conn and try conn.connect
app freezes at this point with no error
Not sure what code to put here, I could paste it all but that would be too much so let me know if any more info is needed:
/**
* Background Async Task to Load all Question by making HTTP Request
*/
class LoadAllImages extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute() {
super.onPreExecute();
// dialog init'd here
}
#Override
protected String doInBackground(String... args) {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
// getting JSON string from URL
JSONObject json = jParser.makeHttpRequest(url_question_details, "GET", params);
// Check your log cat for JSON response
Log.d("All Questions: ", json.toString());
try {
// images found
// Getting Array of questions
images = json.getJSONArray(TAG_IMAGES);
// looping through All questions
for (int i = 0; i < images.length(); i++) {
JSONObject c = images.getJSONObject(i);
// Storing each json item in variable
String id = c.getString(TAG_IMAGEID);
String location = c.getString(TAG_IMAGELOCATION);
URL myFileUrl = null;
try {
myFileUrl = new URL(location);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
conn.setDoInput(true);
conn.connect(); // freezes here
int length = conn.getContentLength();
int[] bitmapData = new int[length];
byte[] bitmapData2 = new byte[length];
InputStream is = conn.getInputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

First of all make sure you added Internet Permission to manifest:
<uses-permission android:name="android.permission.INTERNET" />
outside the application tag in your AndroidManifest.xml
Troubleshooting:
Try access the same URL using your browser
Check if you are not behind proxy or server is not behind proxy
Try pinging the server see and check the latency.
Try catching all exceptions:
Change } catch (IOException e) { to } catch (Exception e) {
If all looks good try this code:
System.setProperty("http.keepAlive", "false");
HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
conn.setUseCaches(false);
conn.setConnectTimeout(30000);
conn.setDoOutput(true);
conn.setDoInput(true);
//conn.connect(); // You are allready connected after openConnection().
If still no luck, try using HttpClient & HttpGet this way:
final HttpClient client = new DefaultHttpClient();
final HttpGet conn = new HttpGet(myFileUrl.toString());
HttpResponse response = client.execute(conn);
InputStream is = response.getEntity().getContent();

I'd at least put both connect and read timeout in, e.g.
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);

I had the exact same issue that drove me crazy to solve. I was already setting the timout params, but the httpurlconnection was hanging on connect() call, or later on getInputStream() if I don't call explicitly connect().
Using a raw thread instead of the asynctask worked for me, without changing anything else...
new Thread(() -> task.doInBackground())
More a workaround than a solution, but better than nothing.

Remove these 2 lines:
conn.setDoInput(true);
conn.connect(); // freezes here
When you do this:
HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
int length = conn.getContentLength();
You are already connected. Calling conn.getContentLength() causes HttpURLConnection to make the connection, sends the request and fetches the response. You don't need to explicitly connect. You also don't need to call setDoInput(true) since that is the default setting.

Related

Why does Android Studio Emulator not run part of my POST request (Java)

Hello stackoverflow users,
I am trying to write a post request (sends an SMS) that is called on a button click. The post request has:
One URL Parameter: api_key
One Header: "Content-Type" = "application/x-www-form-urlencoded"
Three JSON pairs: ("from", "insert#here"), ("to", "insert#here"), and ("body", "Hello, World")
By sending my POST request to a REST API endpoint URL, I want the SMS to send when the user clicks a button. This is what I have:
public class PostSMS extends AsyncTask<Void, String, String>
{
#Override
protected String doInBackground(Void... params) {
try {
MainActivity.text.setText("enteredTry");
URL url = new URL("https://api.apidaze.io/apikey/sms/send?api_secret=apisecret");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
MainActivity.text.setText("connectionBuilt");
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
urlConnection.setRequestMethod("POST");
MainActivity.text.setText("connectionEstablished1");
urlConnection.connect();
MainActivity.text.setText("connectionEstablished23");
// Create JSONObject Request
JSONObject jsonRequest = new JSONObject();
jsonRequest.put("from", "1111111111");
jsonRequest.put("to", "1111111112");
jsonRequest.put("body", "Hello, World");
MainActivity.text.setText("jsonArrayConstructed");
// Write Request to output stream to server
OutputStreamWriter out = new OutputStreamWriter(urlConnection.getOutputStream());
out.write(jsonRequest.toString());
out.close();
MainActivity.text.setText("OutputStream written");
int statusCode = urlConnection.getResponseCode();
String statusMsg = urlConnection.getResponseMessage();
// Connection success. Proceed to fetch the response.
if (statusCode == 200)
{
InputStream it = new BufferedInputStream(urlConnection.getInputStream());
InputStreamReader read = new InputStreamReader(it);
BufferedReader buff = new BufferedReader(read);
StringBuilder dta = new StringBuilder();
String chunks;
while ((chunks = buff.readLine()) != null)
{
dta.append(chunks);
}
String returndata = dta.toString();
return returndata;
}
catch (ProtocolException e)
{
e.printStackTrace();
} catch (MalformedURLException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
} catch (Exception e)
{
e.printStackTrace();
}
return null;
}
}
Upon running this code in an OnClickListener, my TextView object (text in the code) only shows "connectionEstablished1" in the emulator, so it does not run the rest of the program.
After
urlConnection.setRequestMethod("POST");
MainActivity.text.setText("connectionEstablished1");
is run,
the program does not run anymore. There are no compile-time errors.
I have the
<uses-permission android:name="android.permission.INTERNET" />
permission as well.
Thanks!
I checked your code, it's working if you remove MainActivity.text.setText().
As Mike M. pointed out you shouldn't use MainActivity.text.setText() to track progress, you should use Logging for that. If you want to display progress to user you should use onProgressUpdate(String... values) and onPostExecute(String s) that can be overridden in AsyncTask.
Also you could try to debug your app once you get more familiar with Android studio interface, it's easier than checking Logs and StackTraces from catch blocks.

How to close a persistent HTTP Connection without reading

I have an URLConnection which I want to cancel depending on the response code without reading any data. I closely followed the android training to build the following minimal example which
floods the server with requests since no connection is ever released back to the handle pool for reuse
private String downloadUrl(String myurl) throws IOException {
InputStream is = null;
try {
URL url = new URL(myurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query
conn.connect();
int response = conn.getResponseCode();
Log.d(TAG, "The response code is: " + response);
is = conn.getInputStream();
// Do not read anything //String contentAsString = readIt(is, len);
String contentAsString = "notReadingAnything";
return contentAsString;
} finally {
if (is != null) {
is.close();
}
}
}
private class DownloadWebpageTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
try {
String result = new String();
for (int i=0; i<100; i++) {
result += downloadUrl(urls[0]);
}
return result;
} catch (IOException e) {
return "Unable to retrieve web page. URL may be invalid.";
}
}
#Override
protected void onPostExecute(String result) {
Log.d(TAG, "The response is: " + result);
}
}
Despite the docs explicitly stating
But if the response body is long and you are not interested in the rest of it after seeing the beginning, you can close the InputStream
the server quickly reaches its maximum number of connections (50) and goes to 99% workload if I don't read the stream but works fine if I do read it. What is my mistake?
EDIT: Failed solution attempts so far (thanks to #Blackbelt for most of them)
calling conn.disconnect() in the finally block
calling conn.disconnect() instead of is.close() in the finally block
Setting System.setProperty("http.keepAlive", "false"); before the first call
Setting conn.setRequestProperty("Connection", "Close"); before connecting
Setting "{enable_keep_alive", "no"} on the used backend server (Civetweb)
you should call disconnect() too. Accordingly to the documentation
Disconnect. Once the response body has been read, the
HttpURLConnection should be closed by calling disconnect().
Disconnecting releases the resources held by a connection so they may
be closed or reused.
InputStream is = null;
HttpURLConnection conn = null;
try {
URL url = new URL(myurl);
conn = (HttpURLConnection) url.openConnection();
} finally {
if (is != null) {
is.close();
}
if (conn != null) {
conn.disconnect();
}
}
if you still are experiencing issues, is also possible that the bug is backend side

HttpURLConnection: No data in the POST request

I have created a Django Rest server. And I am trying to POST a JSON content in java using HttpURLConnection. However, when I am registering OutputStream in java, the server get a POST request with no JSON content. Hence the server rejecting the request with HTTP response code 400. I did write JSON data just after registering OutputSream. May be POST has been made before writing to OutputStream. The following is the code in JAVA.
public static void post(HttpURLConnection urlConnection1)
throws IOException, InterruptedException {
// urlConnection.setRequestMethod("POST");
URL url = new URL("http://127.0.0.1:8000/message/");
byte[] authStr=Base64.encodeBase64("sp:password".getBytes());
String enc=new String(authStr);
HttpURLConnection urlConnection = (HttpURLConnection) url
.openConnection();
urlConnection.setRequestProperty("Authorization", "Basic "+ enc);
try {
urlConnection.setDoOutput(true);
urlConnection.setChunkedStreamingMode(0);
urlConnection
.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestMethod("POST");
urlConnection.setInstanceFollowRedirects(false);
OutputStream out = urlConnection.getOutputStream();
//Thread.sleep(5000);
writeStream(out);
out.flush();
InputStream in = urlConnection.getInputStream();
readStream(in);
} finally {
urlConnection.disconnect();
}
}
private static void writeStream(OutputStream out) {
// TODO Auto-generated method stub
try {
JSONObject grp = new JSONObject();
JSONObject gp = new JSONObject();
gp.put("id", "g3bj25");
gp.put("from", "someone");
out.write(gp.toString().getBytes());
System.out.println(gp.toString());
} catch (IOException | JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Do I have to make any changes in server side so that it waits for content?
The problem is, that your URL is not complete, the name of the script is missing.
URL url = new URL("http://127.0.0.1:8000/message/");
supposes that you are calling http://127.0.0.1/message/index.php but here you're not allowed to let the index.php (or whatever) implicit.
The script gets called, but the POST data is not sent, or it is truncated by the Webserver when handling the request. I had the same problem and spent hours until I found the reason. Then I did not dig further to find out exactly where the POST data gets dropped.

HttpURLConnection POST-request throws IOException

I'm trying to make a POST-request using android HttpUrlConnection. First I use the example for GET-request from here:
http://developer.android.com/training/basics/network-ops/connecting.html#http-client
It works perfectly (for example I get google.com page). Then I make some changes to make a POST-request: change the request method on POST:
conn.setRequestMethod("POST");
and add this code (got from here: http://developer.android.com/reference/java/net/HttpURLConnection.html):
conn.setDoOutput(true);
conn.setChunkedStreamingMode(0);
OutputStream out = new BufferedOutputStream(conn.getOutputStream());
out.close();
So now the method downloadUrl looks 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(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setDoInput(true);
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setChunkedStreamingMode(0);
OutputStream out = new BufferedOutputStream(conn.getOutputStream());
out.close();
// Starts the query
conn.connect();
int response = conn.getResponseCode();
Log.d(DEBUG_TAG, "The response is: " + response);
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();
}
}
}
And it always throws IOException. Could you help me, what is wrong?
It's because Android won't let you start a network connection on the main UI thread. You have to start a background thread (use AsyncTask) and do it from there.
More detail in this question.
I've sold this problem: the thing was the server didn't accept POST-requests on the selected URL. Changing URL (and server) led to successful request without throwing an exception.

Making PUT request with JSON data using HttpURLConnection is not working

I'm trying to make PUT request with JSON data using HttpURLConnection in Java. The way I do it doesn't work. I get no errors so I don't know what the problem is.
public static void main(String[] args) {
URL url;
try {
url = new URL("http://fltspc.itu.dk/widget/515318fe17450f312b00153d/");
HttpURLConnection hurl = (HttpURLConnection) url.openConnection();
hurl.setRequestMethod("PUT");
hurl.setDoOutput(true);
hurl.setRequestProperty("Content-Type", "application/json");
hurl.setRequestProperty("Accept", "application/json");
String payload = "{'pos':{'left':45,'top':45}}";
OutputStreamWriter osw = new OutputStreamWriter(hurl.getOutputStream());
osw.write(payload);
osw.flush();
osw.close();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
And here is the request I'm actually trying to make:
I was already making GET requests to the resource within the same app and it worked fine. I would be very grateful for all tips on how can I debug that or how can I try to do it some other way. So far I tried only using OutputStream instead of OutputStreamWriter but it doesn't work neither.
The Sun (Oracle) implementation of HttpURLConnection caches the content of your post unless you tell it to be in streaming mode. The content will be sent if you start interaction with the response such as:
hurl.getResponseCode();
Also, according to RFC 4627 you can not use single quotes in your json (although some implementations seem to not care).
So, change your payload to:
String payload = "{\"pos\":{\"left\":45,\"top\":45}}";
This example works for me
public class HttpPut {
public static void main(String[] args) throws Exception {
Random random = new Random();
URL url = new URL("http://fltspc.itu.dk/widget/515318fe17450f312b00153d/");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("PUT");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Accept", "application/json");
OutputStreamWriter osw = new OutputStreamWriter(connection.getOutputStream());
osw.write(String.format("{\"pos\":{\"left\":%1$d,\"top\":%2$d}}", random.nextInt(30), random.nextInt(20)));
osw.flush();
osw.close();
System.err.println(connection.getResponseCode());
}
}

Categories