45

I have an Android app that works fine with Android 2.x and 3.x, but it fails when run on Android 4.x.

The problem is in this section of code:

URL url = new URL("http://blahblah.blah/somedata.xml");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
urlConnection.connect();

InputStream inputStream = urlConnection.getInputStream();

When the application is running on Android 4.x, the getInputStream() call results in a FileNotFoundException. When the same binary is running on earlier versions of Android, it succeeds. The URLs also work fine in web browsers and with curl.

Apparently something about HttpURLConnection has changed in ICS. Does anybody have any idea what has changed, and/or what the fix might be?

Kristopher Johnson
  • 81,409
  • 55
  • 245
  • 302
  • 2
    The docs say that `setDoOutput(true)` implies `setRequestMethod("POST")`. Which do you mean? – Josh Lee Feb 20 '12 at 18:34
  • It's meant to do a GET. (I didn't write the code, so I don't know why `setDoOutput(true)` was there.) – Kristopher Johnson Feb 20 '12 at 18:37
  • FWIW, `setRequestMethod("GET")` and `setDoOutput(true)` appear in a lot of sample code for using `HttpURLConnection`. Where is it documented that it forces a POST? – Kristopher Johnson Feb 20 '12 at 18:54
  • 5
    **HTTP Methods** `HttpURLConnection` uses the `GET` method by default. It will use `POST` if `setDoOutput(true)` has been called. http://developer.android.com/reference/java/net/HttpURLConnection.html – Josh Lee Feb 20 '12 at 19:00
  • it's quite old, but what i did is just i ommited the conn.setRequestMethod("GET") , we set the conn.setDoOutput(true) which means it's a POST and vis versa – dzgeek Oct 09 '15 at 17:45
  • from docs: setDoOutput(true) :Sets the flag indicating whether this {@code URLConnection} allows output. It cannot be set after the connection is established. – Shubham AgaRwal May 09 '16 at 11:14

4 Answers4

102

Try removing the setDoOutput call. Taken from this blog: a blog

Edit: This is needed when using a POST call.

reuscam
  • 1,841
  • 2
  • 18
  • 23
29

A FileNotFoundException may also been thrown if the server returns a bad error code (e.g., 400 or 401). You can handle this as follows:

int responseCode = con.getResponseCode(); //can call this instead of con.connect()
if (responseCode >= 400 && responseCode <= 499) {
    throw new Exception("Bad authentication status: " + responseCode); //provide a more meaningful exception message
}
else {
    InputStream in = con.getInputStream();
    //etc...
}
ban-geoengineering
  • 18,324
  • 27
  • 171
  • 253
  • 2
    I was getting response code 500, because I hadn't set `Content-Type`, thanks for pointing out that this exception might be thrown in those cases. – Ivanka Todorova Feb 10 '16 at 09:12
  • 1
    For anyone wondering why they don't have the "getResponseCode()" method: just cast your connection to a HttpURLConnection – Oded Breiner May 07 '16 at 08:36
  • 1
    Does anyone know *why* Android throws a FileNotFoundException on codes [which clearly aren't 404](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_Error)? – David Lord Jul 07 '16 at 05:07
  • 1
    @DavidLord I had this error because my URL wasn't properly formatted. I used `URLEncoder.encode(myURL, "UTF-8");` for the part of my URL that contained a space character, and it all went well. – OroshiX Dec 01 '16 at 13:49
6

I Don't know why, but dealing manually with redirection resolves the problem.

connection.setInstanceFollowRedirects(false);
Kirill Kulakov
  • 10,035
  • 9
  • 50
  • 67
1

A little late but you can also verify the accepted content. You can add this line to accept all kinds of contents

urlConnection.setRequestProperty("Accept","*/*");
Howy
  • 101
  • 7