This are android tutorials for downloading,parsing and rendering RSS Feeds. We use AsyncTask,XmlPullParser and HttpURLConnection to achieve these. Our adapterview is the ListView.
Example 1 – Android RSS – ListView – Download,Parse,Show Headlines
This is an android RSS example with XmlPullParser,AsyncTask ,HttpURLConnection and ListView..We shall download RSS Feeds from a local website and then parse the feed.We then show parsed images and text news in our ListView.
What we do :
- Connect to Internet and make a HTTP GET request using HtttpURLConnection.
- Download our data in the background thread.
- WE use AsyncTask for our threading.
- WE parse the downloaded xml feeds.
- We shall be parsing using XmlPullParser.
- We show our results in a ListView.
- Our results shall consist of images and text.
- The website we shall be parsing was hosted locally and it was a dummy wordpress site.
SECTION 1 : Our Dependencies and Manifest
AndroidManifest.xml
- Remember we are downloading data from a network.
- Hence we need to add permission to access the internet.
- Or else Android won’t allow us establish connection.
<?xml version="1.0" encoding="utf-8"?> <manifest package="com.tutorials.hp.simplelistviewrss"> <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 : Our Networking and Parsing classes
Connector class
Main Responsibility : ESTABLISH CONNECTION.
- Establishes connection to our server for us.
- We then set up connection properties like Request method.
- In this case we are making a HTTP GET request to our server.
- We shall use HttpURLConnection so our only method shall return its instance .
package com.tutorials.hp.simplelistviewrss.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(); 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; } } }
Downloader class
Main Responsibility : DOWNLOAD XML FEEDS.
- We use our Connector class above to establish a connection.
- If we have a connection then we download data XML feeds from server.
- We download in background using AsyncTask to avoid freezing our user interface.
- Meanwhile we show progress dialog while downloading.
- We dismiss our progress dialog on completion.
- Then we send this downloaded xml feeds to our Data Parser class for it to be processed.
package com.tutorials.hp.simplelistviewrss.m_RSS; import android.app.ProgressDialog; import android.content.Context; import android.os.AsyncTask; import android.widget.ListView; 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; ListView lv; ProgressDialog pd; public Downloader(Context c, String urlAddress, ListView lv) { this.c = c; this.urlAddress = urlAddress; this.lv = lv; } @Override protected void onPreExecute() { super.onPreExecute(); pd=new ProgressDialog(c); pd.setTitle("Fetch Headlines"); pd.setMessage("Fetching....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 { //PARSE new RSSParser(c, (InputStream) data,lv).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; } } }
RSS Parser class
Main Responsibility : DOWNLOAD XML FEEDS.
- It receives raw XML feeds from downloader class.
- It then processes/parses these feeds.
- We use XmlPullParser to parse the feeds.
- It then fills an arraylist of Article Objects with our results.
- It then sends this arraylist to adapter for binding purposes.
package com.tutorials.hp.simplelistviewrss.m_RSS; import android.app.ProgressDialog; import android.content.Context; import android.os.AsyncTask; import android.widget.ArrayAdapter; import android.widget.ListView; 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; ListView lv; ProgressDialog pd; ArrayList<String> headlines=new ArrayList<>(); public RSSParser(Context c, InputStream is, ListView lv) { this.c = c; this.is = is; this.lv = lv; } @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 lv.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); headlines.clear(); String headline=null; Boolean isWebsiteTitle=true; int event=parser.getEventType(); do { String name=parser.getName(); switch (event) { case XmlPullParser.START_TAG: break; case XmlPullParser.TEXT: headline=parser.getText(); break; case XmlPullParser.END_TAG: if(isWebsiteTitle) { isWebsiteTitle=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; } }
Error Tracker class
Main Responsibility : HELP US TRACK CONNECTION EXCEPTIONS AT RUNTIME
- Consists of constants that we shall display when we encounter error at runtime.
package com.tutorials.hp.simplelistviewrss.m_RSS; public class ErrorTracker { public final static String WRONG_URL_FORMAT="Error : Wrong URL Format"; public final static String CONNECTION_ERROR="Error : Unable To Establish Connection"; public final static String IO_EROR="Error : Unable To Read"; }
SECTION 3 : Our Activity
MainActivity class.
Main Responsibility : LAUNCH OUR APP.
- We shall reference the views like ListView and Floating action button here,from our XML Layouts.
- We then execute our Downloader class when Floating action button is clicked.
- We shall also define here our feeds url and parse the data.
package com.tutorials.hp.simplelistviewrss; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.ListView; import com.tutorials.hp.simplelistviewrss.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 ListView lv= (ListView) findViewById(R.id.lv); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { new Downloader(MainActivity.this,urlAddress,lv).execute(); } }); } }
SECTION 5 : Our Layouts
ActivityMain.xml Layout.
- Inflated as our activity’s view.
- Includes our content main.
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout android_layout_width="match_parent" android_layout_height="match_parent" android_fitsSystemWindows="true" tools_context="com.tutorials.hp.simplelistviewrss.MainActivity"> <android.support.design.widget.AppBarLayout android_layout_width="match_parent" android_layout_height="wrap_content" android_theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android_id="@+id/toolbar" android_layout_width="match_parent" android_layout_height="?attr/actionBarSize" android_background="?attr/colorPrimary" app_popupTheme="@style/AppTheme.PopupOverlay" /> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_main" /> <android.support.design.widget.FloatingActionButton android_id="@+id/fab" android_layout_width="wrap_content" android_layout_height="wrap_content" android_layout_gravity="bottom|end" android_layout_margin="@dimen/fab_margin" android_src="@android:drawable/ic_dialog_email" /> </android.support.design.widget.CoordinatorLayout>
ContentMain.xml Layout.
- Defines our view hierarchy.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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.simplelistviewrss.MainActivity" tools_showIn="@layout/activity_main"> <ListView android_id="@+id/lv" android_layout_width="wrap_content" android_layout_height="wrap_content" /> </RelativeLayout>
Example 2 – Android RSS – ListView Multiple Fields – Download,Parse,Show
This is an android RSS example with XmlPullParser,AsyncTask ,HttpURLConnection and ListView..We shall download RSS Feeds from a local website and then parse the feed.We then show parsed images and text news in our ListView.
What we do :
- Connect to Internet and make a HTTP GET request using HtttpURLConnection.
- Download our data in the background thread.
- WE use AsyncTask for our threading.
- WE parse the downloaded xml feeds.
- We shall be parsing using XmlPullParser.
- We show our results in a ListView.
- Our results shall consist of images and text.
- The website we shall be parsing was hosted locally and it was a dummy wordpress site.
Cheers.
SECTION 1 : Our Data Object
Article.java
- Represents a single article.
- The article shall have various properties like name,description,title,date etc.
package com.tutorials.hp.listviewrssmulti_items.m_DataObject; public class Article { String title,description,date,link; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } public String getLink() { return link; } public void setLink(String link) { this.link = link; } }
SECTION 3 : Our Networking and Parsing classes
Connector class
Main Responsibility : ESTABLISH CONNECTION.
- Establishes connection to our server for us.
- We then set up connection properties like Request method.
- In this case we are making a HTTP GET request to our server.
- We shall use HttpURLConnection so our only method shall return its instance .
package com.tutorials.hp.listviewrssmulti_items.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(); 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; } } }
Downloader class
Main Responsibility : DOWNLOAD XML FEEDS.
- We use our Connector class above to establish a connection.
- If we have a connection then we download data XML feeds from server.
- We download in background using AsyncTask to avoid freezing our user interface.
- Meanwhile we show progress dialog while downloading.
- We dismiss our progress dialog on completion.
- Then we send this downloaded xml feeds to our Data Parser class for it to be processed.
package com.tutorials.hp.listviewrssmulti_items.m_RSS; import android.app.ProgressDialog; import android.content.Context; import android.os.AsyncTask; import android.widget.ListView; 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; ListView lv; ProgressDialog pd; public Downloader(Context c, String urlAddress, ListView lv) { this.c = c; this.urlAddress = urlAddress; this.lv = lv; } @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 { //PARSE new RSSParser(c, (InputStream) data,lv).execute(); } } private Object downloadData() { Object connection=Connector.connect(urlAddress); if(connection.toString().startsWith("Error")) { return connection.toString(); } try { HttpURLConnection con= (HttpURLConnection) connection; int responseCode=con.getResponseCode(); if(responseCode==con.HTTP_OK) { InputStream is=new BufferedInputStream(con.getInputStream()); return is; } return ErrorTracker.RESPONSE_ERROR+con.getResponseMessage(); } catch (IOException e) { e.printStackTrace(); return ErrorTracker.IO_EROR; } } }
RSS Parser class
Main Responsibility : DOWNLOAD XML FEEDS.
- It receives raw XML feeds from downloader class.
- It then processes/parses these feeds.
- We use XmlPullParser to parse the feeds.
- It then fills an arraylist of Article Objects with our results.
- It then sends this arraylist to adapter for binding purposes.
package com.tutorials.hp.listviewrssmulti_items.m_RSS; import android.app.ProgressDialog; import android.content.Context; import android.os.AsyncTask; import android.widget.ListView; import android.widget.Toast; import com.tutorials.hp.listviewrssmulti_items.m_DataObject.Article; import com.tutorials.hp.listviewrssmulti_items.m_UI.CustomAdapter; 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; ListView lv; ProgressDialog pd; ArrayList<Article> articles=new ArrayList<>(); public RSSParser(Context c, InputStream is, ListView lv) { this.c = c; this.is = is; this.lv = lv; } @Override protected void onPreExecute() { super.onPreExecute(); pd=new ProgressDialog(c); pd.setTitle("Parse data"); pd.setMessage("Parsing Data...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 lv.setAdapter(new CustomAdapter(c,articles)); }else { Toast.makeText(c,"Unable To Parse",Toast.LENGTH_SHORT).show(); } } private Boolean parseRSS() { try { XmlPullParserFactory factory=XmlPullParserFactory.newInstance(); XmlPullParser parser=factory.newPullParser(); parser.setInput(is,null); int event=parser.getEventType(); String value=null; articles.clear(); Article article=new Article(); do { String name=parser.getName(); switch (event) { case XmlPullParser.START_TAG: if(name.equals("item")) { article=new Article(); } break; case XmlPullParser.TEXT: value=parser.getText(); break; case XmlPullParser.END_TAG: if(name.equals("title")) { article.setTitle(value); }else if(name.equals("description")) { article.setDescription(value); }else if(name.equals("pubDate")) { article.setDate(value); }else if(name.equals("link")) { article.setLink(value); } if(name.equals("item")) { articles.add(article); } break; } event=parser.next(); }while (event != XmlPullParser.END_DOCUMENT); return true; } catch (XmlPullParserException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return false; } }
Error Tracker class
Main Responsibility : HELP US TRACK CONNECTION EXCEPTIONS AT RUNTIME
- Consists of constants that we shall display when we encounter error at runtime.
package com.tutorials.hp.listviewrssmulti_items.m_RSS; public class ErrorTracker { public final static String WRONG_URL_FORMAT="Error : Wrong URL Format"; public final static String CONNECTION_ERROR="Error : Unable To Establish Connection"; public final static String IO_EROR="Error : Unable To Read"; public final static String RESPONSE_ERROR="Error : Bad Response - "; }
SECTION 3 : Adapter class
Custom Adapter class
Main Responsibility : HELPS US BIND CUSTOM DATA TO LISTVIEW.
- You can use one line of code to bind simple data to listview.
- But for custom data like ours,we need an adapter to adapt it.
- We shall use BaseAdapter as our Base class.
- Our BaseAdapter subclass shall receive an arraylist and a context.
package com.tutorials.hp.listviewrssmulti_items.m_UI; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import android.widget.Toast; import com.tutorials.hp.listviewrssmulti_items.R; import com.tutorials.hp.listviewrssmulti_items.m_DataObject.Article; import java.util.ArrayList; public class CustomAdapter extends BaseAdapter { Context c; ArrayList<Article> articles; public CustomAdapter(Context c, ArrayList<Article> articles) { this.c = c; this.articles = articles; } @Override public int getCount() { return articles.size(); } @Override public Object getItem(int position) { return articles.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if(convertView==null) { convertView= LayoutInflater.from(c).inflate(R.layout.model,parent,false); } TextView titleTxt= (TextView) convertView.findViewById(R.id.titleTxt); TextView descTxt= (TextView) convertView.findViewById(R.id.descTxt); TextView dateTxt= (TextView) convertView.findViewById(R.id.dateTxt); final Article article= (Article) this.getItem(position); titleTxt.setText(article.getTitle()); descTxt.setText(article.getDescription().substring(0, 120)); dateTxt.setText(article.getDate()); convertView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(c, article.getTitle(), Toast.LENGTH_SHORT).show(); } }); return convertView; } }
SECTION 4 : Our Activity
MainActivity class.
Main Responsibility : LAUNCH OUR APP.
- We shall reference the views like ListView and Floating action button here,from our XML Layouts.
- We then execute our Downloader class when Floating action button is clicked.
- We shall also define here our feeds url and parse the data.
package com.tutorials.hp.listviewrssmulti_items; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.View; import android.view.Menu; import android.view.MenuItem; import android.widget.ListView; import com.tutorials.hp.listviewrssmulti_items.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 ListView lv= (ListView) findViewById(R.id.lv); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { new Downloader(MainActivity.this,urlAddress,lv).execute(); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
SECTION 5 : Our Layouts
ActivityMain.xml Layout.
- Inflated as our activity’s view.
- Includes our content main.
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout android_layout_width="match_parent" android_layout_height="match_parent" android_fitsSystemWindows="true" tools_context="com.tutorials.hp.listviewrssmulti_items.MainActivity"> <android.support.design.widget.AppBarLayout android_layout_width="match_parent" android_layout_height="wrap_content" android_theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android_id="@+id/toolbar" android_layout_width="match_parent" android_layout_height="?attr/actionBarSize" android_background="?attr/colorPrimary" app_popupTheme="@style/AppTheme.PopupOverlay" /> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_main" /> <android.support.design.widget.FloatingActionButton android_id="@+id/fab" android_layout_width="wrap_content" android_layout_height="wrap_content" android_layout_gravity="bottom|end" android_layout_margin="@dimen/fab_margin" android_src="@android:drawable/ic_dialog_email" /> </android.support.design.widget.CoordinatorLayout>
ContentMain.xml Layout.
- Defines our view hierarchy.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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.listviewrssmulti_items.MainActivity" tools_showIn="@layout/activity_main"> <ListView android_id="@+id/lv" android_layout_width="wrap_content" android_layout_height="wrap_content" /> </RelativeLayout>
Model.xml Layout.
- Inflated as our AdapterView’s viewitems.
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView android_orientation="horizontal" android_layout_width="match_parent" android_layout_margin="10dp" card_view_cardCornerRadius="5dp" card_view_cardElevation="5dp" android_layout_height="200dp"> <LinearLayout android_orientation="vertical" android_layout_width="match_parent" android_layout_height="match_parent"> <TextView android_layout_width="match_parent" android_layout_height="wrap_content" android_textAppearance="?android:attr/textAppearanceLarge" android_text="Title" android_id="@+id/titleTxt" android_padding="10dp" android_textColor="@color/colorAccent" android_textStyle="bold" android_layout_alignParentLeft="true" /> <TextView android_layout_width="wrap_content" android_layout_height="wrap_content" android_textAppearance="?android:attr/textAppearanceLarge" android_text="Description....................." android_lines="3" android_id="@+id/descTxt" android_padding="10dp" android_layout_alignParentLeft="true" /> <TextView android_layout_width="wrap_content" android_layout_height="wrap_content" android_textAppearance="?android:attr/textAppearanceMedium" android_text="Date" android_textStyle="italic" android_id="@+id/dateTxt" /> </LinearLayout> </android.support.v7.widget.CardView>
Example 3 – Android RSS – ListView Master Detail – Download,Parse,Show Headlines [Open Activity]
This is an android RSS Master Detail example with XmlPullParser,AsyncTask ,HttpURLConnection and ListView.We shall download RSS Feeds from a local website and then parse the feed.We then show parsed images and text news in our ListView. We shall handle ItemClicks for our ListView’s ViewItems and open the detail activity,passing in details over there.
What we do :
- Connect to Internet and make a HTTP GET request using HtttpURLConnection.
- Download our data in the background thread.
- WE use AsyncTask for our threading.
- WE parse the downloaded xml feeds.
- We shall be parsing using XmlPullParser.
- We show our results in a ListView.
- This is our master view.It has our ListView.
- When a single ListView viewitem is clicked,we open detail activity.
- The detail view shall show details of a single news feed,like title,description,date etc.
- The website we shall be parsing was hosted locally and it was a dummy wordpress site.
Let’s dive in at the deep end.
SECTION 1 : Our Dependencies and Manifest
AndroidManifest.xml
- Remember we are downloading data from a network.
- Hence we need to add permission to access the internet.
- Or else Android won’t allow us establish connection.
<?xml version="1.0" encoding="utf-8"?> <manifest package="com.tutorials.hp.listviewrssmdetail"> <uses-permission android_name="android.permission.INTERNET"/> </manifest>
SECTION 2 : Our Data Object
Article.java
- Represents a single article.
- The article shall have various properties like name,title,description,date etc.
package com.tutorials.hp.listviewrssmdetail.m_DataObject; public class Article { String title,description,date,guid,link; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } public String getGuid() { return guid; } public void setGuid(String guid) { this.guid = guid; } public String getLink() { return link; } public void setLink(String link) { this.link = link; } }
SECTION 3 : Our Networking and Parsing classes
Connector class
Main Responsibility : ESTABLISH CONNECTION.
- Establishes connection to our server for us.
- We then set up connection properties like Request method.
- In this case we are making a HTTP GET request to our server.
- We shall use HttpURLConnection so our only method shall return its instance .
package com.tutorials.hp.listviewrssmdetail.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(); 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; } } }
Downloader class
Main Responsibility : DOWNLOAD XML FEEDS.
- We use our Connector class above to establish a connection.
- If we have a connection then we download data XML feeds from server.
- We download in background using AsyncTask to avoid freezing our user interface.
- Meanwhile we show progress dialog while downloading.
- We dismiss our progress dialog on completion.
- Then we send this downloaded xml feeds to our Data Parser class for it to be processed.
package com.tutorials.hp.listviewrssmdetail.m_RSS; import android.app.ProgressDialog; import android.content.Context; import android.os.AsyncTask; import android.widget.ListView; 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; ListView lv; ProgressDialog pd; public Downloader(Context c, String urlAddress, ListView lv) { this.c = c; this.urlAddress = urlAddress; this.lv = lv; } @Override protected void onPreExecute() { super.onPreExecute(); pd=new ProgressDialog(c); pd.setTitle("Fetch Articles"); pd.setMessage("Fetching...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 { //PARSER CLASS new RSSParser(c, (InputStream) data,lv).execute(); } } private Object downloadData() { Object connection=Connector.connect(urlAddress); if(connection.toString().startsWith("Error")) { return connection.toString(); } try { HttpURLConnection con= (HttpURLConnection) connection; int responseCode=con.getResponseCode(); if(responseCode==con.HTTP_OK) { InputStream is=new BufferedInputStream(con.getInputStream()); return is; } return ErrorTracker.RESPONSE_EROR+con.getResponseMessage(); } catch (IOException e) { e.printStackTrace(); return ErrorTracker.IO_EROR; } } }
RSS Parser class
Main Responsibility : DOWNLOAD XML FEEDS.
- It receives raw XML feeds from downloader class.
- It then processes/parses these feeds.
- We use XmlPullParser to parse the feeds.
- It then fills an arraylist of Article Objects with our results.
- It then sends this arraylist to adapter for binding purposes.
package com.tutorials.hp.listviewrssmdetail.m_RSS; import android.app.ProgressDialog; import android.content.Context; import android.os.AsyncTask; import android.widget.ListView; import android.widget.Toast; import com.tutorials.hp.listviewrssmdetail.m_DataObject.Article; import com.tutorials.hp.listviewrssmdetail.m_UI.CustomAdapter; 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; ListView lv; ProgressDialog pd; ArrayList<Article> articles=new ArrayList<>(); public RSSParser(Context c, InputStream is, ListView lv) { this.c = c; this.is = is; this.lv = lv; } @Override protected void onPreExecute() { super.onPreExecute(); pd=new ProgressDialog(c); pd.setTitle("Parse Articles"); 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 lv.setAdapter(new CustomAdapter(c,articles)); }else { Toast.makeText(c,"Unable To Parse",Toast.LENGTH_SHORT).show(); } } private Boolean parseRSS() { try { XmlPullParserFactory factory=XmlPullParserFactory.newInstance(); XmlPullParser parser=factory.newPullParser(); parser.setInput(is,null); int event=parser.getEventType(); String tagValue=null; Boolean isSiteMeta=true; articles.clear(); Article article=new Article(); do { String tagName=parser.getName(); switch (event) { case XmlPullParser.START_TAG: if(tagName.equalsIgnoreCase("item")) { article=new Article(); isSiteMeta=false; } break; case XmlPullParser.TEXT: tagValue=parser.getText(); break; case XmlPullParser.END_TAG: if(!isSiteMeta) { if(tagName.equalsIgnoreCase("title")) { article.setTitle(tagValue); }else if(tagName.equalsIgnoreCase("description")) { article.setDescription(tagValue); }else if(tagName.equalsIgnoreCase("pubDate")) { article.setDate(tagValue); }else if(tagName.equalsIgnoreCase("guid")) { article.setGuid(tagValue); }else if(tagName.equalsIgnoreCase("link")) { article.setLink(tagValue); } } if(tagName.equalsIgnoreCase("item")) { articles.add(article); isSiteMeta=true; } break; } event=parser.next(); }while (event != XmlPullParser.END_DOCUMENT); return true; } catch (XmlPullParserException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return false; } }
Error Tracker class
Main Responsibility : HELP US TRACK CONNECTION EXCEPTIONS AT RUNTIME
- Consists of constants that we shall display when we encounter error at runtime.
package com.tutorials.hp.listviewrssmdetail.m_RSS; public class ErrorTracker { public final static String WRONG_URL_FORMAT="Error : Wrong URL Format"; public final static String CONNECTION_ERROR="Error : Unable To Establish Connection"; public final static String IO_EROR="Error : Unable To Read"; public final static String RESPONSE_EROR="Error : Bad Response - "; }
SECTION 3 : Adapter class
Custom Adapter class
Main Responsibility : HELPS US BIND CUSTOM DATA TO LISTVIEW.
- You can use one line of code to bind simple data to listview.
- But for custom data like ours,we need an adapter to adapt it.
- We shall use BaseAdapter as our Base class.
- Our BaseAdapter subclass shall receive an arraylist and a context.
package com.tutorials.hp.listviewrssmdetail.m_UI; import android.content.Context; import android.content.Intent; import android.text.Html; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import com.tutorials.hp.listviewrssmdetail.R; import com.tutorials.hp.listviewrssmdetail.m_DataObject.Article; import com.tutorials.hp.listviewrssmdetail.m_DetailActivity.DetailActivity; import java.util.ArrayList; public class CustomAdapter extends BaseAdapter { Context c; ArrayList<Article> articles; public CustomAdapter(Context c, ArrayList<Article> articles) { this.c = c; this.articles = articles; } @Override public int getCount() { return articles.size(); } @Override public Object getItem(int position) { return articles.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if(convertView==null) { convertView= LayoutInflater.from(c).inflate(R.layout.model,parent,false); } TextView titleTxt= (TextView) convertView.findViewById(R.id.titleTxt); TextView descTxt= (TextView) convertView.findViewById(R.id.descTxt); TextView dateTxt= (TextView) convertView.findViewById(R.id.dateTxt); Article article= (Article) this.getItem(position); final String title=article.getTitle(); final String desc=article.getDescription(); final String date=article.getDate(); final String guid=article.getGuid(); final String link=article.getLink(); titleTxt.setText(title); descTxt.setText(Html.fromHtml(desc)); dateTxt.setText(date); convertView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //OPEN DETAIL ACTIVITY openDetailActivity(title,desc,date,guid,link); } }); return convertView; } private void openDetailActivity(String...details) { Intent i=new Intent(c, DetailActivity.class); i.putExtra("TITLE_KEY",details[0]); i.putExtra("DESC_KEY",details[1]); i.putExtra("DATE_KEY",details[2]); i.putExtra("GUID_KEY",details[3]); i.putExtra("LINK_KEY",details[4]); c.startActivity(i); } }
SECTION 4 : Our Activities
Detail Activity class.
Main Responsibility : DISPLAY SINGLE NEWS ARTICLE DETAILS
- Data shall be passed via Bundle from MainActivity.
- So we simply unpack that data.
- Then show it in our views.
package com.tutorials.hp.listviewrssmdetail.m_DetailActivity; import android.content.Intent; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.text.Html; import android.view.View; import android.widget.TextView; import com.tutorials.hp.listviewrssmdetail.R; public class DetailActivity extends AppCompatActivity { TextView titleTxt,descTxt,dateTxt,guidTxt,linkTxt; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_detail); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); titleTxt= (TextView) findViewById(R.id.titleDetailTxt); descTxt= (TextView) findViewById(R.id.descDetailTxt); dateTxt= (TextView) findViewById(R.id.dateDetailTxt); guidTxt= (TextView) findViewById(R.id.guidDetailTxt); linkTxt= (TextView) findViewById(R.id.linkDetailTxt); Intent i=this.getIntent(); String title=i.getExtras().getString("TITLE_KEY"); String desc=i.getExtras().getString("DESC_KEY"); String date=i.getExtras().getString("DATE_KEY"); String guid=i.getExtras().getString("GUID_KEY"); String link=i.getExtras().getString("LINK_KEY"); titleTxt.setText(title); descTxt.setText(Html.fromHtml(desc)); dateTxt.setText(date); guidTxt.setText(guid); linkTxt.setText(link); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); } }
MainActivity class. Main Responsibility : LAUNCH OUR APP.
- We shall reference the views like ListView and Floating action button here,from our XML Layouts.
- We then execute our Downloader class when Floating action button is clicked.
- We shall also define here our feeds url and parse the data.
package com.tutorials.hp.listviewrssmdetail; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.View; import android.view.Menu; import android.view.MenuItem; import android.widget.ListView; import com.tutorials.hp.listviewrssmdetail.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 ListView lv= (ListView) findViewById(R.id.lv); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { new Downloader(MainActivity.this,urlAddress,lv).execute(); } }); } }
SECTION 5 : Our Layouts
MAINACTIVITY LAYOUTS
ActivityMain.xml Layout.
- Inflated as our activity’s view.
- Includes our content main.
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout android_layout_width="match_parent" android_layout_height="match_parent" android_fitsSystemWindows="true" tools_context="com.tutorials.hp.listviewrssmdetail.MainActivity"> <android.support.design.widget.AppBarLayout android_layout_width="match_parent" android_layout_height="wrap_content" android_theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android_id="@+id/toolbar" android_layout_width="match_parent" android_layout_height="?attr/actionBarSize" android_background="?attr/colorPrimary" app_popupTheme="@style/AppTheme.PopupOverlay" /> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_main" /> <android.support.design.widget.FloatingActionButton android_id="@+id/fab" android_layout_width="wrap_content" android_layout_height="wrap_content" android_layout_gravity="bottom|end" android_layout_margin="@dimen/fab_margin" android_src="@android:drawable/ic_dialog_email" /> </android.support.design.widget.CoordinatorLayout>
ContentMain.xml Layout.
- Defines our view hierarchy.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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.listviewrssmdetail.MainActivity" tools_showIn="@layout/activity_main"> <ListView android_id="@+id/lv" android_layout_width="wrap_content" android_layout_height="wrap_content" /> </RelativeLayout>
Model.xml Layout.
- Inflated as our ListView’s viewitems.
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView android_orientation="horizontal" android_layout_width="match_parent" android_layout_margin="10dp" card_view_cardCornerRadius="5dp" card_view_cardElevation="5dp" android_layout_height="200dp"> <LinearLayout android_orientation="vertical" android_layout_width="match_parent" android_layout_height="match_parent"> <TextView android_layout_width="match_parent" android_layout_height="wrap_content" android_textAppearance="?android:attr/textAppearanceLarge" android_text="Title" android_id="@+id/titleTxt" android_padding="10dp" android_textColor="@color/colorAccent" android_textStyle="bold" android_layout_alignParentLeft="true" /> <TextView android_layout_width="wrap_content" android_layout_height="wrap_content" android_textAppearance="?android:attr/textAppearanceLarge" android_text="Description....................." android_lines="3" android_id="@+id/descTxt" android_padding="10dp" android_layout_alignParentLeft="true" /> <TextView android_layout_width="wrap_content" android_layout_height="wrap_content" android_textAppearance="?android:attr/textAppearanceMedium" android_text="Date" android_textStyle="italic" android_id="@+id/dateTxt" /> </LinearLayout> </android.support.v7.widget.CardView>
DETAILACTIVITY LAYOUTS
ActivityDetail.xml Layout.
- Inflated as our detail activity’s view.
- Includes our content detail.
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout android_layout_width="match_parent" android_layout_height="match_parent" android_fitsSystemWindows="true" tools_context="com.tutorials.hp.gridviewrssmdetail.m_DetailActivity.DetailActivity"> <android.support.design.widget.AppBarLayout android_layout_width="match_parent" android_layout_height="wrap_content" android_theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android_id="@+id/toolbar" android_layout_width="match_parent" android_layout_height="?attr/actionBarSize" android_background="?attr/colorPrimary" app_popupTheme="@style/AppTheme.PopupOverlay" /> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_detail" /> <android.support.design.widget.FloatingActionButton android_id="@+id/fab" android_layout_width="wrap_content" android_layout_height="wrap_content" android_layout_gravity="bottom|end" android_layout_margin="@dimen/fab_margin" android_src="@android:drawable/ic_dialog_email" /> </android.support.design.widget.CoordinatorLayout>
ContentDetail.xml Layout.
- Defines our detail view hierarchy.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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.gridviewrssmdetail.m_DetailActivity.DetailActivity" android_background="#009688" tools_showIn="@layout/activity_detail"> <android.support.v7.widget.CardView android_orientation="horizontal" android_layout_width="match_parent" android_layout_margin="5dp" card_view_cardCornerRadius="10dp" card_view_cardElevation="5dp" android_layout_height="match_parent"> <LinearLayout android_orientation="vertical" android_layout_width="match_parent" android_layout_height="match_parent" android_weightSum="1"> <LinearLayout android_orientation="horizontal" android_layout_width="match_parent" android_layout_height="wrap_content"> <ImageView android_id="@+id/articleDetailImg" android_layout_width="320dp" android_layout_height="wrap_content" android_paddingLeft="10dp" android_layout_alignParentTop="true" android_scaleType="centerCrop" android_src="@drawable/spitzer" /> <LinearLayout android_orientation="vertical" android_layout_width="match_parent" android_layout_height="wrap_content"> <TextView android_id="@+id/titleDetailTxt" android_layout_width="wrap_content" android_layout_height="wrap_content" android_textAppearance="?android:attr/textAppearanceLarge" android_padding="5dp" android_minLines="1" android_textStyle="bold" android_textColor="@color/colorAccent" android_text="Title" /> <TextView android_id="@+id/dateDetailTxt" android_layout_width="wrap_content" android_layout_height="wrap_content" android_textAppearance="?android:attr/textAppearanceLarge" android_padding="5dp" android_minLines="1" android_text="DATE" /> </LinearLayout> </LinearLayout> <TextView android_id="@+id/guidDetailTxt" android_layout_width="wrap_content" android_layout_height="wrap_content" android_textAppearance="?android:attr/textAppearanceMedium" android_padding="5dp" android_minLines="1" android_text="GUID" /> <LinearLayout android_layout_width="fill_parent" android_layout_height="match_parent" android_layout_marginTop="?attr/actionBarSize" android_orientation="vertical" android_paddingLeft="5dp" android_paddingRight="5dp" android_paddingTop="5dp"> <TextView android_id="@+id/linkDetailTxt" android_layout_width="wrap_content" android_layout_height="wrap_content" android_textAppearance="?android:attr/textAppearanceMedium" android_padding="5dp" android_textColor="@color/colorPrimaryDark" android_textStyle="italic" android_text="Link" /> <TextView android_id="@+id/descDetailTxt" android_layout_width="wrap_content" android_layout_height="wrap_content" android_textAppearance="?android:attr/textAppearanceLarge" android_padding="5dp" android_textColor="#0f0f0f" android_minLines="4" android_text="John Doe joined this company on January May 1995 beforesome of you were born.He's been with us through thick and thin.When he came for the first time,he was naive and nervous.Now he is an experienced talent...." /> </LinearLayout> </LinearLayout> </android.support.v7.widget.CardView> </RelativeLayout>
Example 4 – Android RSS – ListView – Headlines With Images and Text
Android RSS Listview images and text example. This is an android RSS images listview example with XmlPullParser,AsyncTask ,HttpURLConnection and ListView..We shall download RSS Feeds from a local website and then parse the feed.We then show parsed images and text news in our ListView.
What we do :
- Connect to Internet and make a HTTP GET request using HtttpURLConnection.
- Download our data in the background thread.
- WE use AsyncTask for our threading.
- WE parse the downloaded xml feeds.
- We shall be parsing using XmlPullParser.
- We show our results in a ListView.
- Our results shall consist of images and text.
- The website we shall be parsing was hosted locally and it was a dummy wordpress site.
Enough.Let’s now dive to the deep end.
SECTION 1 : Our Dependencies and Manifest.
AndroidManifest.xml
- Remember we are downloading data from a network.
- Hence we need to add permission to access the internet.
- Or else Android won’t accept our request for connection.
<?xml version="1.0" encoding="utf-8"?> <manifest package="com.tutorials.hp.listviewrssimagestext"> <uses-permission android_name="android.permission.INTERNET"/> </manifest>
SECTION 2 : Our Data Object
Article.java
- Represents a single article.
- The article shall have various properties like name,title,date etc.
package com.tutorials.hp.listviewrssimagestext.m_DataObject; public class Article { String title,description,date,imageUrl; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } public String getImageUrl() { return imageUrl; } public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; } }
SECTION 3 : Our Networking and Parsing classes
Connector class
Main Responsibility : ESTABLISH CONNECTION.
- Establishes connection to our server for us.
- We then set up connection properties like Request method.
- In this case we are making a HTTP GET request to our server.
- We shall use HttpURLConnection so our only method shall return its instance .
package com.tutorials.hp.listviewrssimagestext.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(); //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; } } }
Downloader class
Main Responsibility : DOWNLOAD XML FEEDS.
- We use our Connector class above to establish a connection.
- If we have a connection then we download data XML feeds from server.
- We download in background using AsyncTask to avoid freezing our user interface.
- Meanwhile we show progress dialog while downloading.
- We dismiss our progress dialog on completion.
- Then we send this downloaded xml feeds to our Data Parser class for it to be processed.
package com.tutorials.hp.listviewrssimagestext.m_RSS; import android.app.ProgressDialog; import android.content.Context; import android.os.AsyncTask; import android.widget.ListView; 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; ListView lv; ProgressDialog pd; public Downloader(Context c, String urlAddress, ListView lv) { this.c = c; this.urlAddress = urlAddress; this.lv = lv; } @Override protected void onPreExecute() { super.onPreExecute(); pd=new ProgressDialog(c); pd.setTitle("Fetch Articles"); pd.setMessage("Fetching...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 { //PARSE RSS new RSSParser(c, (InputStream) data,lv).execute(); } } private Object downloadData() { Object connection=Connector.connect(urlAddress); if(connection.toString().startsWith("Error")) { return connection.toString(); } try { HttpURLConnection con= (HttpURLConnection) connection; int responseCode=con.getResponseCode(); if(responseCode==con.HTTP_OK) { InputStream is=new BufferedInputStream(con.getInputStream()); return is; } return ErrorTracker.RESPONSE_EROR+con.getResponseMessage(); } catch (IOException e) { e.printStackTrace(); return ErrorTracker.IO_EROR; } } }
RSS Parser class
Main Responsibility : DOWNLOAD XML FEEDS.
- It receives raw XML feeds from downloader class.
- It then processes/parses these feeds.
- We use XmlPullParser to parse the feeds.
- It then fills an arraylist of Article Objects with our results.
- It then sends this arraylist to adapter for binding purposes.
package com.tutorials.hp.listviewrssimagestext.m_RSS; import android.app.ProgressDialog; import android.content.Context; import android.os.AsyncTask; import android.widget.ListView; import android.widget.Toast; import com.tutorials.hp.listviewrssimagestext.m_DataObject.Article; import com.tutorials.hp.listviewrssimagestext.m_UI.CustomAdapter; 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; ListView lv; ProgressDialog pd; ArrayList<Article> articles=new ArrayList<>(); public RSSParser(Context c, InputStream is, ListView lv) { this.c = c; this.is = is; this.lv = lv; } @Override protected void onPreExecute() { super.onPreExecute(); pd=new ProgressDialog(c); pd.setTitle("Parse RSS"); 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 lv.setAdapter(new CustomAdapter(c,articles)); }else { Toast.makeText(c,"Unable To Parse",Toast.LENGTH_SHORT).show(); } } private Boolean parseRSS() { try { XmlPullParserFactory factory=XmlPullParserFactory.newInstance(); XmlPullParser parser=factory.newPullParser(); parser.setInput(is,null); int event=parser.getEventType(); String tagValue=null; Boolean isSiteMeta=true; articles.clear(); Article article=new Article(); do { String tagName=parser.getName(); switch (event) { case XmlPullParser.START_TAG: if(tagName.equalsIgnoreCase("item")) { article=new Article(); isSiteMeta=false; } break; case XmlPullParser.TEXT: tagValue=parser.getText(); break; case XmlPullParser.END_TAG: if(!isSiteMeta) { if(tagName.equalsIgnoreCase("title")) { article.setTitle(tagValue); }else if(tagName.equalsIgnoreCase("description")) { String desc=tagValue; article.setDescription(desc.substring(desc.indexOf("/>")+2)); //EXTRACT IMAGE FROM DESCRIPTION String imageUrl=desc.substring(desc.indexOf("src=")+5,desc.indexOf("jpg")+3); article.setImageUrl(imageUrl); }else if(tagName.equalsIgnoreCase("pubDate")) { article.setDate(tagValue); } } if(tagName.equalsIgnoreCase("item")) { articles.add(article); isSiteMeta=true; } break; } event=parser.next(); }while (event != XmlPullParser.END_DOCUMENT); return true; } catch (XmlPullParserException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return false; } }
Error Tracker class
Main Responsibility : HELP US TRACK CONNECTION EXCEPTIONS AT RUNTIME
- Consists of constants that we shall display when we encounter error at runtime.
package com.tutorials.hp.listviewrssimagestext.m_RSS; public class ErrorTracker { public final static String WRONG_URL_FORMAT="Error : URL Format is not valid"; public final static String CONNECTION_ERROR="Error : Unable To Establish Connection"; public final static String IO_EROR="Error : Unable To Read"; public final static String RESPONSE_EROR="Error : Bad Response - "; }
SECTION 3 : Adapter class
Custom Adapter class
Main Responsibility : HELPS US BIND CUSTOM DATA TO LISTVIEW.
- You can use one line of code to bind simple data to listview.
- But for custom data like ours,we need an adapter to adapt it.
- We shall use BaseAdapter as our Base class.
- Our BaseAdapter subclass shall receive an arraylist and a context.
package com.tutorials.hp.listviewrssimagestext.m_UI; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import com.tutorials.hp.listviewrssimagestext.R; import com.tutorials.hp.listviewrssimagestext.m_DataObject.Article; import java.util.ArrayList; public class CustomAdapter extends BaseAdapter { Context c; ArrayList<Article> articles; public CustomAdapter(Context c, ArrayList<Article> articles) { this.c = c; this.articles = articles; } @Override public int getCount() { return articles.size(); } @Override public Object getItem(int position) { return articles.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if(convertView==null) { convertView= LayoutInflater.from(c).inflate(R.layout.model,parent,false); } TextView titleTxt= (TextView) convertView.findViewById(R.id.titleTxt); TextView descTxt= (TextView) convertView.findViewById(R.id.descTxt); TextView dateTxt= (TextView) convertView.findViewById(R.id.dateTxt); ImageView img= (ImageView) convertView.findViewById(R.id.articleImage); Article article= (Article) this.getItem(position); final String title=article.getTitle(); String desc=article.getDescription(); String date=article.getDate(); String imageUrl=article.getImageUrl().replace("localhost","10.0.2.2"); titleTxt.setText(title); descTxt.setText(desc.substring(0,130)); dateTxt.setText(date); PicassoClient.downloadImage(c, imageUrl, img); convertView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(c,title,Toast.LENGTH_SHORT).show(); } }); return convertView; } }
Picasso Client class.
Main Responsibility : DOWNLOAD OUR IMAGES AND CACHE THEM.
- Picasso library shall help us download images when supplied with a URL.
package com.tutorials.hp.listviewrssimagestext.m_UI; import android.content.Context; import android.widget.ImageView; import com.squareup.picasso.Picasso; import com.tutorials.hp.listviewrssimagestext.R; public class PicassoClient { public static void downloadImage(Context c,String imageUrl,ImageView img) { if(imageUrl != null && imageUrl.length()>0) { Picasso.with(c).load(imageUrl).placeholder(R.drawable.placeholder).into(img); }else { Picasso.with(c).load(R.drawable.placeholder).into(img); } } }
SECTION 4 : Our Activity
MainActivity class.
Main Responsibility : LAUNCH OUR APP.
- We shall reference the views like ListView and Floating action button here,from our XML Layouts.
- We then execute our Downloader class when Floating action button is clicked.
- We shall also define here our feeds url and parse the data.
package com.tutorials.hp.listviewrssimagestext; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.View; import android.view.Menu; import android.view.MenuItem; import android.widget.ListView; import com.tutorials.hp.listviewrssimagestext.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 ListView lv= (ListView) findViewById(R.id.lv); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { new Downloader(MainActivity.this,urlAddress,lv).execute(); } }); } }
SECTION 5 : Our Layouts
ActivityMain.xml Layout.
- Inflated as our activity’s view.
- Includes our content main.
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout android_layout_width="match_parent" android_layout_height="match_parent" android_fitsSystemWindows="true" tools_context="com.tutorials.hp.listviewrssimagestext.MainActivity"> <android.support.design.widget.AppBarLayout android_layout_width="match_parent" android_layout_height="wrap_content" android_theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android_id="@+id/toolbar" android_layout_width="match_parent" android_layout_height="?attr/actionBarSize" android_background="?attr/colorPrimary" app_popupTheme="@style/AppTheme.PopupOverlay" /> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_main" /> <android.support.design.widget.FloatingActionButton android_id="@+id/fab" android_layout_width="wrap_content" android_layout_height="wrap_content" android_layout_gravity="bottom|end" android_layout_margin="@dimen/fab_margin" android_src="@android:drawable/ic_dialog_email" /> </android.support.design.widget.CoordinatorLayout>
ContentMain.xml Layout.
- Defines our view hierarchy.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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.listviewrssimagestext.MainActivity" tools_showIn="@layout/activity_main"> <ListView android_id="@+id/lv" android_layout_width="match_parent" android_layout_height="wrap_content" /> </RelativeLayout>
Model.xml Layout.
- Inflated as our AdapterView’s viewitems.
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView android_orientation="horizontal" android_layout_width="match_parent" android_layout_margin="10dp" card_view_cardCornerRadius="5dp" card_view_cardElevation="5dp" android_layout_height="200dp"> <LinearLayout android_orientation="horizontal" android_layout_width="match_parent" android_layout_height="match_parent"> <ImageView android_layout_width="100dp" android_layout_height="wrap_content" android_id="@+id/articleImage" android_padding="10dp" android_src="@drawable/placeholder" /> <LinearLayout android_orientation="vertical" android_layout_width="match_parent" android_layout_height="match_parent"> <TextView android_layout_width="match_parent" android_layout_height="wrap_content" android_textAppearance="?android:attr/textAppearanceLarge" android_text="Title" android_id="@+id/titleTxt" android_padding="10dp" android_textColor="@color/colorAccent" android_textStyle="bold" android_layout_alignParentLeft="true" /> <TextView android_layout_width="wrap_content" android_layout_height="wrap_content" android_textAppearance="?android:attr/textAppearanceLarge" android_text="Description....................." android_lines="3" android_id="@+id/descTxt" android_padding="10dp" android_layout_alignParentLeft="true" /> <TextView android_layout_width="wrap_content" android_layout_height="wrap_content" android_textAppearance="?android:attr/textAppearanceMedium" android_text="Date" android_textStyle="italic" android_id="@+id/dateTxt" /> </LinearLayout> </LinearLayout> </android.support.v7.widget.CardView>
LAST SECTION
- Lets share more tips in OUR FB PAGE.
- To see the XML we were parsing and the website itself please have look at the tutorial at our youtbe channel : ProgramminWizards.
- You’ll also find the demo for this example and step by step explanations.
Cheers.