Showing posts with label JSON. Show all posts
Showing posts with label JSON. Show all posts

Monday, May 23, 2016

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


Last post show a example to "Download and parse blogspot JSON feed". In this post, OnItemClickListener is added to the ListView; for user clicking to open the url in browser, using "Simplest way to open browser using CustomTabsIntent.Builder".


To use CustomTabsIntent.Builder() in your project, you have to edit appbuild.gradle to add dependencies of compile 'com.android.support:customtabs:23.0.0'.

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.4.0'
    compile 'com.android.support:customtabs:23.0.0'
}


Edit MainActivity.java to add OnItemClickListener.
package com.blogspot.android_er.androidparsejson;

import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.customtabs.CustomTabsIntent;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
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);
        listViewFeed.setOnItemClickListener(listViewFeedOnItemClickListener);

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

    AdapterView.OnItemClickListener listViewFeedOnItemClickListener =
            new AdapterView.OnItemClickListener(){
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    FeedItem clickedFeedItem = (FeedItem) parent.getItemAtPosition(position);
                    String url = clickedFeedItem.getUrl();
                    Uri uri = Uri.parse(url);
                    new CustomTabsIntent.Builder()
                            .build()
                            .launchUrl(MainActivity.this, uri);
                }
            };

    /*
    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();
                            }

                        }
                    }

                }
            });
        }
    }
}


Other files, FeedItem.java, activity_main.xml and AndroidManifest.xml, refer last post.

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.