In Android RSS Reader Application using SQLite Part 1 we completed creating required classes. In this part we are starting with designing the application.
6. Designing the Header
The application header has a gradient background color and a plus button on the right side. So create the required xml files to get header layout.
I created a plus button and logo using photoshop in 72x72px, 48x48px and 36x36px dimensions and placed under drawable-hdpi, drawable-mdpi and drawable-ldpi folder.

Create a new xml file under drawable folder and name it as header_gradient.xml and header.xml paste the following code.
header_gradient.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <gradient android:startColor="#db0000" android:centerColor="#c50300" android:endColor="#b30500" android:angle="270"/> </shape>
header.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layoutHeader" android:layout_width="fill_parent" android:layout_height="50dip" android:layout_alignParentTop="true" android:background="@layout/header_gradient" android:orientation="horizontal"> <!-- Logo --> <ImageView android:id="@+id/logo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/logo" android:layout_centerVertical="true" android:layout_marginLeft="10dip"/> <!-- Plus Button --> <ImageButton android:id="@+id/btnAddSite" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_marginRight="5dip" android:layout_weight="1" android:background="@null" android:src="@drawable/plus" android:layout_centerVertical="true" /> </RelativeLayout>
The above xml will generate following header layout.

7. Displaying all websites in listview (from SQLite)
In our application the first screen will display all the websites in listview from SQLite database.
Open your main activity file (in my case AndroidRSSReaderApplicationActivity.java) and type the following code. In the following code
-> First a background thread is called to load the websites from sqlite table.
-> In background thread websites are displayed in listview.
-> Also the header plus button has click event which will launch add new website activity.
-> If you long press on list item it will show you context menu with delete option.
Create a xml file called site_list.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="#ffffff"> <!-- Header --> <include layout="@layout/header"/> <ListView android:id="@+id/list" android:layout_below="@id/layoutHeader" android:layout_width="fill_parent" android:layout_height="wrap_content" android:divider="#bababa" android:dividerHeight="1dp" android:listSelector="@drawable/list_selector" android:background="#ffffff" android:cacheColorHint="#00000000"/> </RelativeLayout>
Also create an xml file listview single row
site_list_row.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="5dip"> <!-- SQLite row id / hidden by default --> <TextView android:id="@+id/sqlite_id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone"/> <!-- web site title --> <TextView android:id="@+id/title" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingTop="8dip" android:paddingLeft="8dip" android:paddingBottom="4dip" android:textSize="18dip" android:textColor="#1a1a1a" /> <!-- web site url --> <TextView android:id="@+id/link" android:layout_height="wrap_content" android:layout_width="wrap_content" android:paddingLeft="8dip" android:paddingBottom="6dip" android:textSize="15dip" android:textColor="#c00300" android:layout_below="@id/title"/> <!-- Right end Arrow --> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/arrow" android:layout_alignParentRight="true" android:layout_centerVertical="true"/> </RelativeLayout>
AndroidRSSReaderApplicationActivity.java
package com.androidhive.rssreader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ImageButton; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; public class AndroidRSSReaderApplicationActivity extends Activity { // Progress Dialog private ProgressDialog pDialog; // Array list for list view ArrayList<HashMap<String, String>> rssFeedList; RSSParser rssParser = new RSSParser(); RSSFeed rssFeed; // button add new website ImageButton btnAddSite; // array to trace sqlite ids String[] sqliteIds; public static String TAG_ID = "id"; public static String TAG_TITLE = "title"; public static String TAG_LINK = "link"; // List view ListView lv; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.site_list); btnAddSite = (ImageButton) findViewById(R.id.btnAddSite); // Hashmap for ListView rssFeedList = new ArrayList<HashMap<String, String>>(); /** * Calling a background thread which will load * web sites stored in SQLite database * */ new loadStoreSites().execute(); // selecting single ListView item lv = (ListView) findViewById(R.id.list); // Launching new screen on Selecting Single ListItem lv.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // getting values from selected ListItem String sqlite_id = ((TextView) view.findViewById(R.id.sqlite_id)).getText().toString(); // Starting new intent Intent in = new Intent(getApplicationContext(), ListRSSItemsActivity.class); // passing sqlite row id in.putExtra(TAG_ID, sqlite_id); startActivity(in); } }); /** * Add new website button click event listener * */ btnAddSite.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { Intent i = new Intent(getApplicationContext(), AddNewSiteActivity.class); // starting new activity and expecting some response back // depending on the result will decide whether new website is // added to SQLite database or not startActivityForResult(i, 100); } }); } /** * Response from AddNewSiteActivity.java * if response is 100 means new site is added to sqlite * reload this activity again to show * newly added website in listview * */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // if result code 100 if (resultCode == 100) { // reload this screen again Intent intent = getIntent(); finish(); startActivity(intent); } } /** * Building a context menu for listview * Long press on List row to see context menu * */ @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { if (v.getId()==R.id.list) { menu.setHeaderTitle("Delete"); menu.add(Menu.NONE, 0, 0, "Delete Feed"); } } /** * Responding to context menu selected option * */ @Override public boolean onContextItemSelected(MenuItem item) { AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo(); int menuItemIndex = item.getItemId(); // check for selected option if(menuItemIndex == 0){ // user selected delete // delete the feed RSSDatabaseHandler rssDb = new RSSDatabaseHandler(getApplicationContext()); WebSite site = new WebSite(); site.setId(Integer.parseInt(sqliteIds[info.position])); rssDb.deleteSite(site); //reloading same activity again Intent intent = getIntent(); finish(); startActivity(intent); } return true; } /** * Background Async Task to get RSS data from URL * */ class loadStoreSites extends AsyncTask<String, String, String> { /** * Before starting background thread Show Progress Dialog * */ @Override protected void onPreExecute() { super.onPreExecute(); pDialog = new ProgressDialog( AndroidRSSReaderApplicationActivity.this); pDialog.setMessage("Loading websites ..."); pDialog.setIndeterminate(false); pDialog.setCancelable(false); pDialog.show(); } /** * getting all stored website from SQLite * */ @Override protected String doInBackground(String... args) { // updating UI from Background Thread runOnUiThread(new Runnable() { public void run() { RSSDatabaseHandler rssDb = new RSSDatabaseHandler( getApplicationContext()); // listing all websites from SQLite List<WebSite> siteList = rssDb.getAllSites(); sqliteIds = new String[siteList.size()]; // loop through each website for (int i = 0; i < siteList.size(); i++) { WebSite s = siteList.get(i); // creating new HashMap HashMap<String, String> map = new HashMap<String, String>(); // adding each child node to HashMap key => value map.put(TAG_ID, s.getId().toString()); map.put(TAG_TITLE, s.getTitle()); map.put(TAG_LINK, s.getLink()); // adding HashList to ArrayList rssFeedList.add(map); // add sqlite id to array // used when deleting a website from sqlite sqliteIds[i] = s.getId().toString(); } /** * Updating list view with websites * */ ListAdapter adapter = new SimpleAdapter( AndroidRSSReaderApplicationActivity.this, rssFeedList, R.layout.site_list_row, new String[] { TAG_ID, TAG_TITLE, TAG_LINK }, new int[] { R.id.sqlite_id, R.id.title, R.id.link }); // updating listview lv.setAdapter(adapter); registerForContextMenu(lv); } }); return null; } /** * After completing background task Dismiss the progress dialog * **/ protected void onPostExecute(String args) { // dismiss the dialog after getting all products pDialog.dismiss(); } } }
The above activity will produce following screen which will list all the websites in listview (If you have any websites stored in websites table).

8. Adding new website to SQLite
Create new activity and layout which allows user to add new website to application. The screen will be launched if user clicks on plus button in header.
Create a xml layout to called add_site.xml
add_site.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="#ffffff"> <TextView android:id="@+id/lblUrl" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Enter URL (http://abc.com)" android:textColor="#c50300" android:padding="10dip" android:textStyle="bold"/> <EditText android:id="@+id/txtUrl" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginRight="10dip" android:layout_marginLeft="10dip" android:layout_below="@id/lblUrl" android:inputType="textUri" android:hint="Enter website url" android:singleLine="true"/> <Button android:id="@+id/btnSubmit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/txtUrl" android:text="Submit" android:layout_marginTop="8dip" android:layout_marginLeft="8dip"/> <Button android:id="@+id/btnCancel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/btnSubmit" android:layout_below="@id/txtUrl" android:text="Cancel" android:layout_marginTop="8dip" android:layout_marginLeft="8dip" android:windowSoftInputMode="stateVisible|adjustPan"/> <TextView android:id="@+id/lblMessage" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="#ff0000" android:padding="10dip" android:layout_marginTop="15dip" android:layout_below="@id/btnSubmit"/> </RelativeLayout>
Also create a new class file and name it as AddNewSiteActivity.java and type following code. In the following
-> Website url is validated once user click on submit button.
-> If it is a valid url a background thread is called to get rss link from url.
-> Once RSS url found a new row will be created in SQLite websites table.
AddNewSiteActivity.java
package com.androidhive.rssreader; import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class AddNewSiteActivity extends Activity { Button btnSubmit; Button btnCancel; EditText txtUrl; TextView lblMessage; RSSParser rssParser = new RSSParser(); RSSFeed rssFeed; // Progress Dialog private ProgressDialog pDialog; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.add_site); // buttons btnSubmit = (Button) findViewById(R.id.btnSubmit); btnCancel = (Button) findViewById(R.id.btnCancel); txtUrl = (EditText) findViewById(R.id.txtUrl); lblMessage = (TextView) findViewById(R.id.lblMessage); // Submit button click event btnSubmit.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { String url = txtUrl.getText().toString(); // Validation url Log.d("URL Length", "" + url.length()); // check if user entered any data in EditText if (url.length() > 0) { lblMessage.setText(""); String urlPattern = "^http(s{0,1})://[a-zA-Z0-9_/\\-\\.]+\\.([A-Za-z/]{2,5})[a-zA-Z0-9_/\\&\\?\\=\\-\\.\\~\\%]*"; if (url.matches(urlPattern)) { // valid url new loadRSSFeed().execute(url); } else { // URL not valid lblMessage.setText("Please enter a valid url"); } } else { // Please enter url lblMessage.setText("Please enter website url"); } } }); // Cancel button click event btnCancel.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { finish(); } }); } /** * Background Async Task to get RSS data from URL * */ class loadRSSFeed extends AsyncTask<String, String, String> { /** * Before starting background thread Show Progress Dialog * */ @Override protected void onPreExecute() { super.onPreExecute(); pDialog = new ProgressDialog(AddNewSiteActivity.this); pDialog.setMessage("Fetching RSS Information ..."); pDialog.setIndeterminate(false); pDialog.setCancelable(false); pDialog.show(); } /** * getting Inbox JSON * */ @Override protected String doInBackground(String... args) { String url = args[0]; rssFeed = rssParser.getRSSFeed(url); Log.d("rssFeed", " "+ rssFeed); if (rssFeed != null) { Log.e("RSS URL", rssFeed.getTitle() + "" + rssFeed.getLink() + "" + rssFeed.getDescription() + "" + rssFeed.getLanguage()); RSSDatabaseHandler rssDb = new RSSDatabaseHandler( getApplicationContext()); WebSite site = new WebSite(rssFeed.getTitle(), rssFeed.getLink(), rssFeed.getRSSLink(), rssFeed.getDescription()); rssDb.addSite(site); Intent i = getIntent(); // send result code 100 to notify about product update setResult(100, i); finish(); } else { // updating UI from Background Thread runOnUiThread(new Runnable() { public void run() { lblMessage.setText("Rss url not found. Please check the url or try again"); } }); } return null; } /** * After completing background task Dismiss the progress dialog * **/ protected void onPostExecute(String args) { // dismiss the dialog after getting all products pDialog.dismiss(); // updating UI from Background Thread runOnUiThread(new Runnable() { public void run() { if (rssFeed != null) { } } }); } } }

9. Displaying RSS feed articles in listview
We have another screen where list of articles will be displayed in listview once user selects a particular website.
Create xml file called rss_item_list.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="#ffffff"> <!-- Header --> <include layout="@layout/header"/> <ListView android:id="@android:id/list" android:layout_below="@id/layoutHeader" android:layout_width="fill_parent" android:layout_height="wrap_content" android:divider="#bababa" android:dividerHeight="1dp" android:listSelector="@drawable/list_selector" android:background="#ffffff" android:cacheColorHint="#00000000"/> </RelativeLayout>
For single list item row – rss_item_list_row.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="8dip" > <TextView android:id="@+id/page_url" android:layout_width="fill_parent" android:layout_height="wrap_content" android:visibility="gone"/> <!-- Article title --> <TextView android:id="@+id/title" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingBottom="1dip" android:textSize="18dip" android:textStyle="bold" android:textColor="#303030" /> <!-- published date --> <TextView android:id="@+id/pub_date" android:layout_below="@id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingBottom="3dip" android:textSize="14dip" android:textColor="#b70400"/> <!-- article description --> <TextView android:id="@+id/link" android:layout_height="wrap_content" android:layout_width="wrap_content" android:paddingBottom="6dip" android:textSize="15dip" android:textColor="#8d8d8d" android:layout_below="@id/pub_date"/> </RelativeLayout>
Create a new activity file called ListRSSItemsActivity.java and type the following code. In the following code
-> Site rss link will be received from previous activity.
-> a new background thread which fetches the rss from rss link and parse it
-> Once rss parsing is done, all the articles are displayed in listview
ListRSSItemsActivity.java
package com.androidhive.rssreader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import android.app.ListActivity; import android.app.ProgressDialog; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; import android.widget.Toast; public class ListRSSItemsActivity extends ListActivity { // Progress Dialog private ProgressDialog pDialog; // Array list for list view ArrayList<HashMap<String, String>> rssItemList = new ArrayList<HashMap<String,String>>(); RSSParser rssParser = new RSSParser(); List<RSSItem> rssItems = new ArrayList<RSSItem>(); RSSFeed rssFeed; private static String TAG_TITLE = "title"; private static String TAG_LINK = "link"; private static String TAG_DESRIPTION = "description"; private static String TAG_PUB_DATE = "pubDate"; private static String TAG_GUID = "guid"; // not used @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.rss_item_list); // get intent data Intent i = getIntent(); // SQLite Row id Integer site_id = Integer.parseInt(i.getStringExtra("id")); // Getting Single website from SQLite RSSDatabaseHandler rssDB = new RSSDatabaseHandler(getApplicationContext()); WebSite site = rssDB.getSite(site_id); String rss_link = site.getRSSLink(); /** * Calling a backgroung thread will loads recent articles of a website * @param rss url of website * */ new loadRSSFeedItems().execute(rss_link); // selecting single ListView item ListView lv = getListView(); // Launching new screen on Selecting Single ListItem lv.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Intent in = new Intent(getApplicationContext(), DisPlayWebPageActivity.class); // getting page url String page_url = ((TextView) view.findViewById(R.id.page_url)).getText().toString(); Toast.makeText(getApplicationContext(), page_url, Toast.LENGTH_SHORT).show(); in.putExtra("page_url", page_url); startActivity(in); } }); } /** * Background Async Task to get RSS Feed Items data from URL * */ class loadRSSFeedItems extends AsyncTask<String, String, String> { /** * Before starting background thread Show Progress Dialog * */ @Override protected void onPreExecute() { super.onPreExecute(); pDialog = new ProgressDialog( ListRSSItemsActivity.this); pDialog.setMessage("Loading recent articles..."); pDialog.setIndeterminate(false); pDialog.setCancelable(false); pDialog.show(); } /** * getting all recent articles and showing them in listview * */ @Override protected String doInBackground(String... args) { // rss link url String rss_url = args[0]; // list of rss items rssItems = rssParser.getRSSFeedItems(rss_url); // looping through each item for(RSSItem item : rssItems){ // creating new HashMap HashMap<String, String> map = new HashMap<String, String>(); // adding each child node to HashMap key => value map.put(TAG_TITLE, item.getTitle()); map.put(TAG_LINK, item.getLink()); map.put(TAG_PUB_DATE, item.getPubdate()); String description = item.getDescription(); // taking only 200 chars from description if(description.length() > 100){ description = description.substring(0, 97) + ".."; } map.put(TAG_DESRIPTION, description); // adding HashList to ArrayList rssItemList.add(map); } // updating UI from Background Thread runOnUiThread(new Runnable() { public void run() { /** * Updating parsed items into listview * */ ListAdapter adapter = new SimpleAdapter( ListRSSItemsActivity.this, rssItemList, R.layout.rss_item_list_row, new String[] { TAG_LINK, TAG_TITLE, TAG_PUB_DATE, TAG_DESRIPTION }, new int[] { R.id.page_url, R.id.title, R.id.pub_date, R.id.link }); // updating listview setListAdapter(adapter); } }); return null; } /** * After completing background task Dismiss the progress dialog * **/ protected void onPostExecute(String args) { // dismiss the dialog after getting all products pDialog.dismiss(); } } }

10. Displaying single article (WebView)
The final step is to display single article in webview. So create a new xml layout for webview
Create a new xml file called webview.xml and type the following code.
<?xml version="1.0" encoding="utf-8"?> <WebView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/webpage" android:layout_width="fill_parent" android:layout_height="fill_parent" />
And create a activity class file called DisPlayWebPageActivity.java and type the following code. In the following code
-> Webpage url is received from previous activity
-> After the url is displayed using a webview
DisPlayWebPageActivity.java
package com.androidhive.rssreader; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.KeyEvent; import android.webkit.WebView; import android.webkit.WebViewClient; public class DisPlayWebPageActivity extends Activity { WebView webview; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.webview); Intent in = getIntent(); String page_url = in.getStringExtra("page_url"); webview = (WebView) findViewById(R.id.webpage); webview.getSettings().setJavaScriptEnabled(true); webview.loadUrl(page_url); webview.setWebViewClient(new DisPlayWebPageActivityClient()); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_BACK) && webview.canGoBack()) { webview.goBack(); return true; } return super.onKeyDown(keyCode, event); } private class DisPlayWebPageActivityClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } } }

11. Deleting Website from SQLite (Long press on Listview to see Context menu)
To delete a website from sqlite database long press on listview to see the context menu with delete option. If you select the delete option that website will be deleted from database.
In your main activity class(AndroidRSSReaderApplicationActivity.java) check for following methods which will create a context menu and perform delete operation on selecting the menu.
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {} // will create context menu for listview @Override public boolean onContextItemSelected(MenuItem item) {} // will respond to menu selection
