Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Android

Rebuilding blog reader app

So I'm rebuilding the Android blog reader app to use my Wordpress blog and Jetpack's REST API.

The first problem obvious to me is modifying the way the JSONObject is created in GetBlogPostTask as the current implementation expects the array to be formatted for the Treehouse data.

Using the new URL of my blog the app now returns a NegativeArraySizeException: -1 on int contentLength = connection.getContentLength(); during doInBackground.

I'm guessing the JSON data from Wordpress does not contain a ContentLength header so I have to use another method to set the following char[] array.

Any pointers about how to go about this?

3 Answers

Kate Hoferkamp
Kate Hoferkamp
5,205 Points

Okay, so I have been playing with this all day, and I got part of this to work, well I got the title to show on the list. Here is what I did:

try {
                URL blogFeedUrl = new URL("https://public-api.wordpress.com/rest/v1/sites/www.thetechguysblog.com/posts");
                HttpURLConnection connection = (HttpURLConnection) blogFeedUrl.openConnection();
                connection.connect();

                responseCode = connection.getResponseCode();

                if (responseCode == HttpURLConnection.HTTP_OK){
                    InputStream inputStream = connection.getInputStream();

                    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                    StringBuilder stringBuilder = new StringBuilder();
                    String line = "";

                    while ((line = reader.readLine()) != null) {
                        stringBuilder.append(line + "\n");
                    }
                   String responseData = stringBuilder.toString();

                    jsonResponse = new JSONObject(responseData);
                }
                else {
                    Log.i(TAG, "Unsuccessful HTTP Response Code: " + responseCode);
                }
            }

Oh wow. Ok, I think I get everything you did but could you run me through the while statement and how exactly you're using stringbuilder object?

Kate Hoferkamp
Kate Hoferkamp
5,205 Points

I do believe I got this all working! WOOOOOOOO. I was so frustrated with this all day. It was tons of fun to work out. You ready for all of this?

First, change KEY_AUTHOR to equal "name". This is because the "author" field is actually an object within the post object.

Second, in your handleBlogResponse() method there is a few things to do: Add: JSONObject authorDetails = post.getJSONObject("author"); right after the JSONObject post declaration. Change: String author = post.getString(KEY_AUTHOR); to String author = authorDetails.getString(KEY_AUTHOR);

Lastly, put the following code in the if statement in the try for the GetBlogPostsTask:

InputStream inputStream = connection.getInputStream();
                    //Reader reader = new InputStreamReader(inputStream);
                    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                    StringBuilder stringBuilder = new StringBuilder();
                    String line = "";
                    while ((line = reader.readLine()) != null) {
                        stringBuilder.append(line + "\n");
                    }
                   String responseData = stringBuilder.toString();

So here is the two complete methods with the new changes:

 private class GetBlogPostsTask extends AsyncTask<Object, Void, JSONObject> {
        @Override
        protected JSONObject doInBackground(Object... arg0) {

            int responseCode = -1;
            JSONObject jsonResponse = null;

            try {
                URL blogFeedUrl = new URL("https://public-api.wordpress.com/rest/v1/sites/www.thetechguysblog.com/posts");
                HttpURLConnection connection = (HttpURLConnection) blogFeedUrl.openConnection();
                connection.connect();

                responseCode = connection.getResponseCode();
                if (responseCode == HttpURLConnection.HTTP_OK){
                    InputStream inputStream = connection.getInputStream();

                    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                    StringBuilder stringBuilder = new StringBuilder();
                    String line = "";

                    while ((line = reader.readLine()) != null) {
                        stringBuilder.append(line + "\n");
                    }

                   String responseData = stringBuilder.toString();

                    jsonResponse = new JSONObject(responseData);
                }
                else {
                    Log.i(TAG, "Unsuccessful HTTP Response Code: " + responseCode);
                }
            }
            catch (MalformedURLException e){
                logException(e);
            }
            catch (IOException e){
                logException(e);
            }
            catch (Exception e){
                logException(e);
            }

            return jsonResponse;
        }
 private void handleBlogResponse() {
        //Hide progress bar
        mProgressBar.setVisibility(View.INVISIBLE);
        if (mBlogData == null){
            updateDisplayForError();
        }
        else {
            try {
                JSONArray jsonPosts = mBlogData.getJSONArray("posts");
                ArrayList<HashMap<String, String>>  blogPosts = new ArrayList<HashMap<String, String>>();

                for (int i = 0; i < jsonPosts.length(); i++){
                    //Get single object
                    JSONObject post = jsonPosts.getJSONObject(i);
                    JSONObject authorDetails = post.getJSONObject("author");

                    //Get title and author of single object
                    String title = post.getString(KEY_TITLE);
                    String author = authorDetails.getString(KEY_AUTHOR);

                    //Convert title and author HTML to Strings
                    title = Html.fromHtml(title).toString();
                    author = Html.fromHtml(author).toString();

                    //Create HashMap for blogPost
                    HashMap<String, String> blogPost = new HashMap<String, String>();
                    blogPost.put(KEY_TITLE, title);
                    blogPost.put(KEY_AUTHOR, author);

                    //Add HashMap to ArrayList blogPosts
                    blogPosts.add(blogPost);
                }

                //Adapt Array mBlogPostTitles to a list that displays
                String[] keys = {KEY_TITLE, KEY_AUTHOR};
                int[] ids = {android.R.id.text1, android.R.id.text2};
                SimpleAdapter adapter = new SimpleAdapter(this, blogPosts, android.R.layout.simple_list_item_2, keys, ids);
                setListAdapter(adapter);
            }
            catch (JSONException e){
                logException(e);
            }
        }
    }
    private final String KEY_AUTHOR = "name";

Oh wow. Ok, I think I get everything you did but could you run me through the while statement and how exactly you're using stringbuilder object?

Kate Hoferkamp
Kate Hoferkamp
5,205 Points

Yeah of course, so a StringBuilder is a sequence of chars. So i used it as a char[] with no definable length, in that I was just adding char's for each line that was read from the reader.

So each loop through the while statement, it was reading a line from the reader, and passing it to the variable line. When line was not null, and therefore not at the end of the json, it would add the line that was read to the end of the StringBuilder. When there was nothing left, the while did not run because it was at the end, and therefore exited the loop.

Since the StringBuilder is just a sequence or array of char's I used the toString method to convert it into a String so that the rest of the code we had previously still worked.

Did you try this and get it to work for you?

Hopefully this all helped and you understand it, if not feel free to ask anything else =]. Sorry I've been terrible at responding, I don't check treehouse enough apparently! =P You can always reach me through twitter if that's easier.

Kate Hoferkamp
Kate Hoferkamp
5,205 Points

What is the url you are using to get the JSON data? If you pull that up in your browser, and have an app on your browser that formats it nicely, you would be able to see how it is formatted, and therefore me able to see if it has a length, and if so what is it called.

Hi Kate,

The Url is

https://public-api.wordpress.com/rest/v1/sites/www.thetechguysblog.com/posts

I'm using the WP Dev console, I think length parameter is called "found", not sure though. Even so, would I still be calling getContentLength() or another method?

Kate Hoferkamp
Kate Hoferkamp
5,205 Points

It's odd that found = 31, but the number of posts is 20.. I wonder what found is actually calculating.. On the treehouse blog, count and the number of posts are the same. But I would try it with found.

I think you would still use getContentLength(), but what number does that return? Can you log that value and see what it is? It should be 20..

It returns a NegativeArraySizeException, I'm pretty sure number of posts is actually 31, I think 20 is the number of object parameters.

Kate Hoferkamp
Kate Hoferkamp
5,205 Points

I think the problem is the response url you are using is not setting a content-length in the header, which the treehouse blog did. -1 means that it could not find the content-length. There's a few things you can do, the easiest would be to add it server side, if possible, before the output stream. If you can't do that, you have to use find a different way to get the data in. Here is one example: http://stackoverflow.com/questions/5428639/android-url-connection-getcontentlength-returning-negative-value

Ok so I just changed onListItemClick to get the correct string from the JSON object and boom links open in webview and posts are getting pulled from the web correctly on my phone.

Thanks a mil, you ran rings around my code and I'm glad for it! Super awesome! Next I'm going to add images to the textview for each post. About to go through next Ribbit stage and see what other features I can add.

Kate Hoferkamp
Kate Hoferkamp
5,205 Points

Awesome! I'm glad I could help! It was quite the learning experience for us both, haha. My stronghold has always been in java, so it's been amazing to expand on it and learn some new things. Glad we got it working!