Android RSS - Simple GridView - Show Headlines

December 19, 2017 Oclemy Android XML, Android GridView, Android HttpURLConnection 5 minutes, 53 seconds

XmlPullParser Overview

  • Is an interface, xmlPull.v1.XmlPullParser.
  • Added in API level 1;
  • Defines how to parse Xml documents.
  • Has two key methods : next() and nextToken();
  • We use XmlPullParserFactory to create its instance.
  • The method next() enables us work with higher level events while nextToken() at a lower level.
  • Invoking getEventType() enable us know the current state of event of the parser.
  • The first event state is _STARTDOCUMENT, calling next() moves us to the next event.
  • A couple of high level events accessible to next() include:
  1. START_TAG => Raised when XML start tag was read.
  2. TEXT => Raised when text content was read. The text itself can be retrieved using the getText()
  3. END_TAG => End tag was read.
  4. END_DOCUMENT => The very last event.

Lets proceed on to our example. Tutorial Points

  • We are parsing a wordpress news website RSS Feeds
  • We extract headlines and show in simple gridview.
  • Have a look at the video tutorial here to see the xml and website.

SECTION 1 : SETUP

Build.Gradle

  • Our dependencies.
apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.tutorials.hp.simplegridviewrss"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

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

Our Manifest

  • Add internet connection permission.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tutorials.hp.simplegridviewrss">

    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 SECTION 2 : NETWORK

Our Connector Class

  • Establish Connection for us.
  • We then make a HTTP GET request to server.
  • We use HttpURLConnection.
package com.tutorials.hp.simplegridviewrss.m_RSS;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class Connector {

    public static Object connect(String urlAddress)
    {
        try {
            URL url=new URL(urlAddress);
            HttpURLConnection con= (HttpURLConnection) url.openConnection();

            //CONNECTION PROPERTIES
            con.setRequestMethod("GET");
            con.setConnectTimeout(15000);
            con.setReadTimeout(15000);
            con.setDoInput(true);

            return con;

        } catch (MalformedURLException e) {
            e.printStackTrace();
            return ErrorTracker.WRONG_URL_FORMAT;

        } catch (IOException e) {
            e.printStackTrace();
            return ErrorTracker.CONNECTION_ERROR;
        }
    }

}

Our RSS Downloader Class

  • Call connector to connect.
  • Subclasses AsyncTask.
  • Download data in background thread while showing progress dialog.
  • Calls Parser class to parse data when through.
package com.tutorials.hp.simplegridviewrss.m_RSS;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.GridView;
import android.widget.Toast;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;

public class Downloader extends AsyncTask<Void,Void,Object> {

    Context c;
    String urlAddress;
    GridView gv;

    ProgressDialog pd;

    public Downloader(Context c, String urlAddress, GridView gv) {
        this.c = c;
        this.urlAddress = urlAddress;
        this.gv = gv;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        pd=new ProgressDialog(c);
        pd.setTitle("Fetch data");
        pd.setMessage("Fetching Data...Please wait");
        pd.show();

    }

    @Override
    protected Object doInBackground(Void... params) {
        return this.downloadData();
    }

    @Override
    protected void onPostExecute(Object data) {
        super.onPostExecute(data);
        pd.dismiss();
        if(data.toString().startsWith("Error"))
        {
            Toast.makeText(c,data.toString(),Toast.LENGTH_SHORT).show();
        }else {
            //CALL PARSER CLASS
            new RSSParser(c, (InputStream) data,gv).execute();
        }
    }

    private Object downloadData()
    {
        Object connection=Connector.connect(urlAddress);
        if(connection.toString().startsWith("Error"))
        {
            return connection.toString();
        }

        try
        {
            HttpURLConnection con= (HttpURLConnection) connection;
            InputStream is=new BufferedInputStream(con.getInputStream());

            return is;

        } catch (IOException e) {
            e.printStackTrace();
            return ErrorTracker.IO_EROR;
        }
    }
}

 SECTION 4 : RSS PARSING

Our RSS Parser Class

  • Receives data from Downloader class.
  • Parses this data using XmlPullParser.
  • Subclasses asynctask.
  • We parse in background thread using asynctask as well.
  • Sends the parsed data to adapter class for it be bound.
package com.tutorials.hp.simplegridviewrss.m_RSS;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.ArrayAdapter;
import android.widget.GridView;
import android.widget.Toast;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

public class RSSParser extends AsyncTask<Void,Void,Boolean> {

    Context c;
    InputStream is;
    GridView gv;

    ProgressDialog pd;
    ArrayList<String> headlines=new ArrayList<>();

    public RSSParser(Context c, InputStream is, GridView gv) {
        this.c = c;
        this.is = is;
        this.gv = gv;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        pd=new ProgressDialog(c);
        pd.setTitle("Parse Data");
        pd.setMessage("Parsing...Please wait");
        pd.show();
    }

    @Override
    protected Boolean doInBackground(Void... params) {
        return this.parseRSS();
    }

    @Override
    protected void onPostExecute(Boolean isParsed) {
        super.onPostExecute(isParsed);
        pd.dismiss();
        if(isParsed)
        {
            //BIND DATA
            gv.setAdapter(new ArrayAdapter<String>(c,android.R.layout.simple_list_item_1,headlines));

        }else {
            Toast.makeText(c,"Unable To Parse",Toast.LENGTH_SHORT).show();
        }
    }

    private Boolean parseRSS()
    {
        try
        {
            XmlPullParserFactory factory=XmlPullParserFactory.newInstance();
            XmlPullParser parser=factory.newPullParser();

            //SET STREAM
            parser.setInput(is,null);
            String headline=null;

            int event=parser.getEventType();
            Boolean isWebsiteTiltle=true;

            do {
                String name=parser.getName();

                switch (event)
                {
                    case XmlPullParser.START_TAG:
                        break;

                    case XmlPullParser.TEXT:
                        headline=parser.getText();
                        break;

                    case XmlPullParser.END_TAG:

                        if(isWebsiteTiltle)
                        {
                            isWebsiteTiltle=false;
                        }else if(name.equals("title"))
                       {
                           headlines.add(headline);
                       }
                        break;
                }

                event=parser.next();

            }
            while (event != XmlPullParser.END_DOCUMENT);

            return true;

        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return false;
    }
}

SECTION 6 : MAIN ACTIVITY

Our MainActivity

  • Our launcher activity
  • Executes our downloader class on fab button click.
package com.tutorials.hp.simplegridviewrss;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.GridView;

import com.tutorials.hp.simplegridviewrss.m_RSS.Downloader;

public class MainActivity extends AppCompatActivity {

    final static String urlAddress="http://10.0.2.2/galacticnews/index.php/feed/";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);

        final GridView gv= (GridView) findViewById(R.id.gv);

        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                 new Downloader(MainActivity.this,urlAddress,gv).execute();
            }
        });
    }

}

SECTION 5 : LAYOUTS

ContentMain.xml

  • Contains our AdapterView.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.tutorials.hp.simplegridviewrss.MainActivity"
    tools:showIn="@layout/activity_main">

    <GridView
        android:id="@+id/gv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:numColumns="3" />
</RelativeLayout>

Android RSS Feeds GridView

Comments