Rendering RSS data in Android
The XML data from the RSS feed is now safely stored in memory in an instance of RSSFeed, which in turn contains a number of RSSItems in a convenient
List structure. The purposes of an RSS reader are to manage the data and display it in
an orderly fashion to the user. Here is where the specifics of Android user interface coding and resources come into play. In this section, you will learn about the Android user interface implementation and the way the RSS data is displayed.
The RSSReader application's startup Activity is the class RSSReader. The entry point of an Activity is the onCreate method. This method is responsible for boot-strapping the user interface and in some cases, such as this one, the method also initiates subsequent operations beyond creating the user interface. Looking at the onCreate method found in RSSReader.java, and showing in Listing 8, you can see that the structure of the application is very simple.
Listing 8.
The RSSReader's onCreate method
private RSSFeed feed = null;
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
// go get our feed!
feed = getFeed(RSSFEEDOFCHOICE);
// display UI
UpdateDisplay();
}
|
The onCreate method performs three functions:
- Sets up the user interface which is identified by
R.layout.mainand represents the layout contained in main.xml - Sets up an instance of the
RSSFeedclass by calling thegetFeed()method - Updates the user interface to reflect the RSS feed contents through the
UpdateDisplay()method.
The RSSReader Activity's user interface includes two
TextViews and a ListView. The TextViews display the channel title and publication date,
while the ListView displays the list of RSSItems in the RSSFeed.
Listing 9 contains the layout for the primary Activity's user interface.
Listing 9. main.xml contains the user interface definition for the
RSSReader Activity
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Android RSSReader"
android:id="@+id/feedtitle"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/feedpubdate"
/>
<ListView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/itemlist"
/>
</LinearLayout>
|
The layout in main.xml has very simple user interface views. Note the presence of the android:id attributes in each of the views. These are necessary because the application dynamically updates the content of each of these views.
Look at the UpdateDisplay method in Listing 10 to see how
the RSSFeed data connects to the user interface. Recall that an instance of the RSSFeed class now contains the RSS data. The UpdateDisplay method is tasked with taking the RSS data and rendering it through the Android user interface.
Listing 10.
UpdateDisplay method connects the data to the user interface
private void UpdateDisplay()
{
TextView feedtitle = (TextView) findViewById(R.id.feedtitle);
TextView feedpubdate = (TextView) findViewById(R.id.feedpubdate);
ListView itemlist = (ListView) findViewById(R.id.itemlist);
if (feed == null)
{
feedtitle.setText("No RSS Feed Available");
return;
}
feedtitle.setText(feed.getTitle());
feedpubdate.setText(feed.getPubDate());
ArrayAdapter<RSSItem> adapter = new
ArrayAdapter<RSSItem>(this,android.R.layout.
simple_list_item_1,feed.getAllItems());
itemlist.setAdapter(adapter);
itemlist.setSelection(0);
itemlist.setOnItemClickListener(this);
}
|
Following along in Listing 10, the UpdateDisplay method starts out by connecting the two TextView objects and a ListView object to the layout through the findViewById() method, passing in the respective identifiers.
If the RSSFeed is null, the method displays a message indicating that RSS feed is available.
The channel title and publication dates are displayed in the respective TextView objects.
To connect the list of RSSItems to the ListView, you create
an instance of the ArrayAdapter class. This parameterized class is constructed to manage items of type RSSItem. The layout of the list is governed by the built-in resource known as simple_list_item_1, which is essentially a list where each entry supports a single line of text. You also pass in a list of all RSSItem entries in your RSSFeed through the getAllItems() method of the RSSFeed class. If you recall, the RSSItem class overrides the default toString() method to allow the ArrayAdapter to get meaningful representations for displaying in the ListView. Listing 11 shows how the method does some simple formatting to make sure the text fits into the ListView nicely.
Listing 11. Overriding the default
toString() method of the RSSItem class
public String toString()
{
// limit how much text you display
if (_title.length() > 42)
{
return _title.substring(0, 42) + "...";
}
return _title;
}
|
This ArrayAdapter is assigned to the ListView and the first entry is selected by calling the setSelection method with an argument of zero.
Lastly, you want to setup a listener to respond to item selections with the setOnItemClickListener method. The RSSReader class implements the OnItemClickListener interface: public class RSSReader extends Activity implements OnItemClickListener.
The listener functionality is implemented in the onItemClick method as seen in Listing 12.
Listing 12.
onItemClick implementation
public void onItemClick(AdapterView parent, View v, int position, long id)
{
Log.i(tag,"item clicked! [" + feed.getItem(position).getTitle() + "]");
Intent itemintent = new Intent(this,ShowDescription.class);
Bundle b = new Bundle();
b.putString("title", feed.getItem(position).getTitle());
b.putString("description", feed.getItem(position).getDescription());
b.putString("link", feed.getItem(position).getLink());
b.putString("pubdate", feed.getItem(position).getPubDate());
itemintent.putExtra("android.intent.extra.INTENT", b);
startSubActivity(itemintent,0);
}
|
When an item in the ListView is selected, the application displays the Description
element of the chosen RSSItem. Look at the code in
onItemClick and note three things:
- The creation of an Intent which is necessary to launch another Activity, the
ShowDescriptionActivity which is defined in ShowDescription.java - The use of a Bundle to pass data to the invoked activity
- Starting the
ShowDescriptionactivity as a sub activity, which aids in bringing about a synchronous effect to the application
The ShowDescription Activity provides the next level of detail for the chosen RSSItem, as seen in Figure 2.
Figure 2. Next level of detail for the chosen
RSSItem
The ShowDescription class is listed in Listing 13. Note the process of un-Bundling the RSSItem data and formatting a string to be used in the user interface.
Listing 13.
ShowDescription activity
package com.msi.androidrss;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import android.content.Intent;
import android.view.*;
public class ShowDescription extends Activity
{
public void onCreate(Bundle icicle)
{
super.onCreate(icicle);
setContentView(R.layout.showdescription);
String theStory = null;
Intent startingIntent = getIntent();
if (startingIntent != null)
{
Bundle b = startingIntent.getBundleExtra("android.intent.extra.INTENT");
if (b == null)
{
theStory = "bad bundle?";
}
else
{
theStory = b.getString("title") + "\n\n" + b.getString("pubdate")
+ "\n\n" + b.getString("description").replace('\n',' ')
+ "\n\nMore information:\n" + b.getString("link");
}
}
else
{
theStory = "Information Not Found.";
}
TextView db= (TextView) findViewById(R.id.storybox);
db.setText(theStory);
Button backbutton = (Button) findViewById(R.id.back);
backbutton.setOnClickListener(new Button.OnClickListener()
{
public void onClick(View v)
{
finish();
}
});
}
}
|
Take some care to ensure the Activity does not try to process a null Bundle or display erroneous data. Make sure that the variable theStory always has something valid assigned.
The code has a simple Button OnClickListener to terminate this Activity. Because this Activity was launched with the startSubActivity() method, this call to finish() results in control returning to the calling Activity, which is RSSReader.
Note that the textual representation of this description includes a hyperlink. Android
takes care this of automatically with the attribute android:autoLink="all" as seen in Listing 14.
Listing 14. ShowDescription.xml defines the user interface for the ShowDescription Activity
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:autoLink="all"
android:text="story goes here ...."
android:id="@+id/storybox"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Back"
android:id="@+id/back"
/>
</LinearLayout>
|
With the text linking, to launch a Web site through the link of RSSItem is a zero code operation, as seen in Figures 3 and 4.
Figure 3. Web site references in text are automatically hyper-linked
Figure 4 shows the launched Web page from the RSSItem link element. This demonstrates the power and efficiency of RSS. You see a topic of interest in the List of items when you select it. You see a concise abstract and if that conveys a satisfactory amount of information, you're done. If your curiosity is further piqued, click on the link and you have even more detailed information.
Figure 4. A launched Web page from the
RSSItem link element
That's it. You have a functioning RSS reader!
In the source code, the final item to look at is the RSSReader.java file where the menus are setup. Recall that this tutorial does not address the topic of selecting the RSS feed nor refreshing it other than on startup, However, you'll note some hooks provided to do this in a future tutorial. Listing 15 contains the two methods required to implement menu behavior.
Listing 15. Menu handling methods
public boolean onCreateOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu(menu);
menu.add(0,0,"Choose RSS Feed");
menu.add(0,1,"Refresh");
Log.i(tag,"onCreateOptionsMenu");
return true;
}
public boolean onOptionsItemSelected(Menu.Item item){
switch (item.getId()) {
case 0:
Log.i(tag,"Set RSS Feed");
return true;
case 1:
Log.i(tag,"Refreshing RSS Feed");
return true;
}
return false;
}
|
The onCreateOptionsMenu() is called once during the life cycle of the Activity and allows the creation of menu items. The second argument to the method call is a unique identifier for the menu.
The onOptionsItemSelected method is invoked when the user
selects an item. Using the menu item's identifier through the getId() method, it is straight-forward to respond to a specific menu selection.
It is beyond the scope of this tutorial to expand on this functionality; these methods are included as a starting point for enhancements to the Android RSS reader!



