Sunday, May 22, 2016

Download and parse blogspot JSON feed

This example show how to download and parse blogspot JSON feed.


The url of my feed is http://android-er.blogspot.com/feeds/posts/default?alt=json.

Actually I don't know the format of blogspot json feed, I use Online JSON Viewer (http://jsonviewer.stack.hu/) to guess. This video show how:


In my example, I download and parse the json feed in AsyncTask, Only post title and url retrieved, and display as String in ListView.


Create a new class FeedItem.java
package com.blogspot.android_er.androidparsejson;

public class FeedItem {
    private String title;
    private String url;

    FeedItem(String title, String url){
        this.title = title;
        this.url = url;
    }

    public String getTitle(){
        return title;
    }

    public String getUrl(){
        return url;
    }

    @Override
    public String toString() {
        return title + " :\n" + url;
    }
}


MainActivity.java
package com.blogspot.android_er.androidparsejson;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    Button btnLoadFeed;
    TextView textViewFeedUrl;
    ListView listViewFeed;

    List<FeedItem> listFeedItems;
    ListAdapter adapterFeed;

    String myFeed = "http://android-er.blogspot.com/feeds/posts/default?alt=json";
    //String myFeed = "http://arduino-er.blogspot.com/feeds/posts/default?alt=json";
    //String myFeed = "http://helloraspberrypi.blogspot.com/feeds/posts/default?alt=json";
    //String myFeed = "http://photo-er.blogspot.com/feeds/posts/default?alt=json";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnLoadFeed = (Button)findViewById(R.id.loadfeed);
        textViewFeedUrl = (TextView)findViewById(R.id.feedurl);
        listViewFeed = (ListView)findViewById(R.id.listviewfeed);

        listFeedItems = new ArrayList<>();
        adapterFeed = new ArrayAdapter<FeedItem>(
                this, android.R.layout.simple_list_item_1, listFeedItems);
        listViewFeed.setAdapter(adapterFeed);

        btnLoadFeed.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                textViewFeedUrl.setText(myFeed);
                new JsonTask(listFeedItems, listViewFeed).execute(myFeed);
            }
        });
    }

    /*
    JsonTask:
    AsyncTask to download and parse JSON Feed of blogspot in background
     */
    private class JsonTask extends AsyncTask<String, FeedItem, String> {

        List<FeedItem> jsonTaskList;
        ListView jsonTaskListView;

        public JsonTask(List<FeedItem> targetList, ListView targetListView) {
            super();
            jsonTaskList = targetList;
            jsonTaskListView = targetListView;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            jsonTaskList.clear();
            jsonTaskListView.invalidateViews();
        }

        @Override
        protected String doInBackground(String... params) {

            try {
                final String queryResult = sendQuery(params[0]);
                parseQueryResult(queryResult);
            } catch (IOException e) {
                e.printStackTrace();

                final String eString = e.toString();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this,
                                eString,
                                Toast.LENGTH_LONG).show();
                    }
                });

            } catch (JSONException e) {
                e.printStackTrace();

                final String eString = e.toString();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this,
                                eString,
                                Toast.LENGTH_LONG).show();
                    }
                });
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(FeedItem... values) {
            FeedItem newItem = values[0];
            jsonTaskList.add(newItem);
            jsonTaskListView.invalidateViews();
        }

        private String sendQuery(String query) throws IOException {
            String queryReturn = "";
            URL queryURL = new URL(query);

            HttpURLConnection httpURLConnection = (HttpURLConnection)queryURL.openConnection();

            if(httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK){
                InputStreamReader inputStreamReader =
                        new InputStreamReader(httpURLConnection.getInputStream());
                BufferedReader bufferedReader = new BufferedReader(
                        inputStreamReader, 8192);
                String line = null;
                while((line = bufferedReader.readLine()) != null){
                    queryReturn += line;
                }

                bufferedReader.close();
            }


            return queryReturn;
        }

        private void parseQueryResult(String json) throws JSONException {
            JSONObject jsonObject = new JSONObject(json);
            final JSONObject jsonObject_feed = jsonObject.getJSONObject("feed");
            final JSONArray jsonArray_entry = jsonObject_feed.getJSONArray("entry");

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if(jsonArray_entry == null){
                        Toast.makeText(MainActivity.this,
                                "jsonArray_entry == null",
                                Toast.LENGTH_LONG).show();
                    }else{
                        Toast.makeText(MainActivity.this,
                                String.valueOf(jsonArray_entry.length()),
                                Toast.LENGTH_LONG).show();
                        for(int i=0; i<jsonArray_entry.length(); i++){
                            try {
                                JSONObject thisEntry = (JSONObject) jsonArray_entry.get(i);
                                JSONObject thisEntryTitle = thisEntry.getJSONObject("title");
                                String thisEntryTitleString = thisEntryTitle.getString("$t");

                                JSONArray jsonArray_EntryLink = thisEntry.getJSONArray("link");

                                //search for the link element with rel="alternate"
                                //I assume it's one and only one element with rel="alternate",
                                //and its href hold the link to the page
                                for(int j=0; j<jsonArray_EntryLink.length(); j++){
                                    JSONObject thisLink = (JSONObject) jsonArray_EntryLink.get(j);
                                    try{
                                        String thisLinkRel = thisLink.getString("rel");
                                        if(thisLinkRel.equals("alternate")){
                                            try{
                                                String thisLinkHref = thisLink.getString("href");
                                                FeedItem thisElement = new FeedItem(
                                                        thisEntryTitleString.toString(),
                                                        thisLinkHref);
                                                publishProgress(thisElement);
                                                break;
                                            }catch (JSONException e){
                                                //no such mapping exists
                                            }
                                        }
                                    }catch (JSONException e){
                                        //no such mapping exists
                                    }

                                }
                                
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }

                        }
                    }

                }
            });
        }
    }
}


layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:orientation="vertical"
    tools:context="com.blogspot.android_er.androidparsejson.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:id="@+id/loadfeed"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Load Feed"/>
    <TextView
        android:id="@+id/feedurl"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold|italic"/>
    <ListView
        android:id="@+id/listviewfeed"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>


uses-permission of "android.permission.INTERNET" is needed in AndroidManifest.xml.


download filesDownload the files .

Next:
Parse blogspot JSON feed: detect item clicked to open in browser using CustomTabsIntent


Remark@2017-05-20:
This video show how I TRY to locate the thumbnail from the JSON feed. In order to find the url of the thumbnail of the posts, you have to search "media$thumbnail" elements in the feeds. But I haven't actually implemented the code.


3 comments:

Unknown said...

Working Good.Thanks

BR Softech said...

This is really very interesting. This blog contain too much information about parse android app development.

Ronny said...

hello , can you help me ?
please share tutorial how to impementation to RecylerView from JSON Blogspot

Thank You Sir.