1

I'm trying to learn Android development by creating the movies app from the Google Udacity course. In my code below upon executing urlConnection.connect(), the code automatically goes to the finally block without any errors/exceptions.

Can you please help me see what's wrong with my code? Thanks!

    public class FetchMoviesTask extends AsyncTask<Void, Void, String> {

    private final String LOG_TAG = FetchMoviesTask.class.getSimpleName();

    protected String doInBackground(Void... params) {

        String JSONResponse = null;

        //These are declared outside as they'll be used in both try and finally  blocks
        BufferedReader reader = null;
        HttpURLConnection urlConnection = null;

        try {

            //construct your URL from a URI
            Uri.Builder URIbuilder = new Uri.Builder();
            URIbuilder.scheme("http")
                    .authority("api.themoviedb.org")
                    .appendPath("3")
                    .appendPath("movie")
                    .appendPath("popular")
                    .appendQueryParameter("api_key", BuildConfig.TMDB_API_KEY);

            //instantiate URL
            URL popularURL = new URL(URIbuilder.toString());

            Log.v(LOG_TAG, "Built URL: " + popularURL.toString());

            //create and open HTTP connection
            urlConnection = (HttpURLConnection) popularURL.openConnection();
            urlConnection.setRequestMethod("GET");
            urlConnection.connect();

            //InputStream is needed to read the response
            //http://developer.android.com/reference/java/net/HttpURLConnection.html
            InputStream inputStream = urlConnection.getInputStream();
            if (inputStream == null) {
                Log.e(LOG_TAG, "Null input stream");
                return null; //no data returned from HTTP request
            }

            //!!want to see what InputStream looks like
            Log.v(LOG_TAG, "inputStream.toString(): " + inputStream.toString());

            //BufferedReader is used to wrap a Reader and buffer its input
            //to read InputStream, a "reader" is required and that's InputStreamReader (duh)
            //http://developer.android.com/reference/java/io/BufferedReader.html
            reader = new BufferedReader(new InputStreamReader(inputStream));

            //!!want to see what BufferedReader looks like
            Log.v(LOG_TAG, "reader.toString(): " + reader.toString());

            //replaced StringBuffer w/ StringBuilder. will it work?
            StringBuilder builder = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                // Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
                // But it does make debugging a *lot* easier if you print out the completed
                // buffer for debugging.
                builder.append(line + "\n");
            }

            if (builder.length() == 0) return null; //empty stream. no point in parsing

            JSONResponse = builder.toString();

            Log.v(LOG_TAG, "JSON Response: " + JSONResponse);

            return parseJSON(JSONResponse);

        } catch (IOException e) {
            Log.e(LOG_TAG, "Error", e);
            return null;
        } catch (JSONException e) {
            Log.e(LOG_TAG, "Error parsing JSON", e);
            return null;
        } catch (Error e) {
            Log.e(LOG_TAG, "Unknown error", e);
        } finally {
            if (urlConnection != null) urlConnection.disconnect();
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    Log.e(LOG_TAG, "Error closing stream", e);
                }
            }

            //will only be triggered if there's an error getting/parsing data
            return null;
        }

    }
Karl Jamoralin
  • 1,240
  • 1
  • 14
  • 27
  • 2
    Do you get ANY Log output? – Julian Kroné Mar 06 '16 at 16:46
  • A finally block is guaranteed to execute if at least one line of code within the try is executed..not if an exception occurs. – pczeus Mar 06 '16 at 16:48
  • That's what's puzzling me -- I only get the first log output to display the built URL. After that there's no further log output suggesting that subsequent logs weren't executed at all. – Karl Jamoralin Mar 06 '16 at 16:48
  • 1
    The only condition it can directly go to finally block is InputStream is null but I can see a log entry for that – Raghu K Nair Mar 06 '16 at 16:50
  • 2
    Possible duplicate of [Java try-finally return design question](http://stackoverflow.com/questions/4185340/java-try-finally-return-design-question) – pczeus Mar 06 '16 at 16:50
  • 3
    "the code automatically goes to the finally block" -- in your code, this will occur if `connect()` throws something that is not an `IOException`, a `JSONException`, or an `Error`. For example, if you do not have the `INTERNET` permission, you will get a `SecurityException`, which is none of those. – CommonsWare Mar 06 '16 at 16:54
  • Looks like that's exactly what I'm missing! Thanks for bringing it up CommonsWare! – Karl Jamoralin Mar 06 '16 at 17:09

2 Answers2

0

CommonsWare pointed me to the possible cause of the issue, which was a missing INTERNET permission. Adding it solved my problem. Thanks for all the responses!

Karl Jamoralin
  • 1,240
  • 1
  • 14
  • 27
-2

The problem is this comment in your code:

//will only be triggered if there's an error getting/parsing data

That's false.

The return in the try block won't be ignored if a finally block is defined, only if that finally block also includes a return.

In other words, if you have "return" in both try and finally, the one inside finally is the one which gets executed.

Source: Java try-finally return design question

Edit:
You may want to check this out: Does finally always execute in Java?

Community
  • 1
  • 1
Chaoz
  • 2,119
  • 1
  • 20
  • 39
  • This should not be answered, but should have been marked as a duplicate, referring to the link you provided. – pczeus Mar 06 '16 at 16:50
  • Thanks for the answer -- but that's not my issue here. My issue is that after the connect() statement, the code after it was skipped and went straight to the finally block, without providing clues or even going to the catch clauses. – Karl Jamoralin Mar 06 '16 at 16:51
  • Do you mean that the `Log.v`s don't show? If yes, are you sure the ones before the `URL.connect()` show? – Chaoz Mar 06 '16 at 16:53
  • Yes, this log before Url.connect() can be seen in the logs: Log.v(LOG_TAG, "Built URL: " + popularURL.toString()); After that, there are no more logs. – Karl Jamoralin Mar 06 '16 at 16:53
  • 1
    Then you should clarify your question. – pczeus Mar 06 '16 at 16:54
  • 1
    The problem the OP mentions occurs before the problem mentioned here. – user207421 Mar 06 '16 at 18:36