Tonight I whipped up a quick port of Mike Chamber's code that demonstrates RSS parsing in ActionScript. I took his code and built a simple native AIR for Mobile application from it. The more I work with Flash Builder "Burrito" and Flex SDK "Hero" (the new AIR framework with mobile support), the more I really appreciate how easy Adobe has made mobile development. I've got a full application here that downloads a RSS feed, displays it nicely, and allows you to read the entry text. While this isn't that special, what impresses me is that steps done to make it easy to create the application. For example, it's trivial to tell the application to move from one screen to another. It's trivial to pass data from one view to another. These are all things that aren't terribly complex in a traditional AIR application - but frankly there is nothing at all wrong with making things even simpler. Let's take a look at the code - and again - credit goes to Mike Chambers for the original.
Let's start off with the first page of the application. This view is responsible for:
- Getting the RSS from a remote feed, in my case, AndroidGator.com
- Turning the RSS string into data. This is done with an open source library called as3syndicationlib
- Setting the RSS items into a list.
- Providing a way to click from the list into a detail
Here is that template in full. I'm going to skip over the things covered in Mike's post.
<fx:Script>
<![CDATA[
import com.adobe.utils.XMLUtil;
import com.adobe.xml.syndication.rss.Item20;
import com.adobe.xml.syndication.rss.RSS20; import mx.collections.ArrayCollection; [Bindable] private var COMPANY:String = "AndroidGator";
private var URL:String = "http://www.androidgator.com";
private var RSSURL:String = "http://feeds.feedburner.com/AndroidgatorcomFeed"; [Bindable] private var rssItems:ArrayCollection; private var loader:URLLoader; private function init():void { loader = new URLLoader(); //request pointing to feed
var request:URLRequest = new URLRequest(RSSURL);
request.method = URLRequestMethod.GET; //listen for when the data loads
loader.addEventListener(Event.COMPLETE, onDataLoad); //listen for error events
loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError); //load the feed data
loader.load(request); } //called once the data has loaded from the feed
private function onDataLoad(e:Event):void {
//get the raw string data from the feed
var rawRSS:String = URLLoader(e.target).data; //parse it as RSS
parseRSS(rawRSS); } private function parseRSS(data:String):void { //XMLSyndicationLibrary does not validate that the data contains valid
//XML, so you need to validate that the data is valid XML.
//We use the XMLUtil.isValidXML API from the corelib library.
if(!XMLUtil.isValidXML(data))
{
trace("Feed does not contain valid XML.");
return;
} //create RSS20 instance
var rss:RSS20 = new RSS20(); //parse the raw rss data
rss.parse(data); //get all of the items within the feed
var items:Array = rss.items;
rssItems = new ArrayCollection(items);
} private function loadEntry(evt:Event):void {
navigator.pushView(ItemView,{item:rssListing.selectedItem}); } private function onIOError(e:IOErrorEvent):void {
} private function onSecurityError(e:SecurityErrorEvent):void {
}
]]>
</fx:Script> <s:layout>
<s:VerticalLayout paddingTop="10" paddingLeft="5" paddingRight="5" gap="20" />
</s:layout> <s:List id="rssListing" dataProvider="{rssItems}" width="100%" height="100%" click="loadEntry(event)" labelField="title" /> <s:Button width="100%" label="Visit Website" click="navigateToURL(new URLRequest(URL))" /> </s:View>
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="News from {COMPANY}" viewActivate="init()">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
As I said, I won't bother discussing what Mike's post does, but let me point out a few things. I've got 3 variables that define how the application works and is displayed. COMPANY (which should really be SITE) is simply a label for the application. It tells you what site's RSS feed is being used. URL and RSSURL are the main URL and RSS feed URLs respectively. Make note of how we can load the main URL using the navigateToURL function. Nice and simple, right? Now take a look at the loadEntry function, repeated below.
private function loadEntry(evt:Event):void {
navigator.pushView(ItemView,{item:rssListing.selectedItem});
}
This is exactly what I was talking about in terms of Adobe going out of it's way to simplify things. The pushView API does exactly what you would imagine - put up a view in front of the user. The second argument is a set of data that is passed into the view. This makes it easy to handle navigation between different views and pass data around. Love it. Here is how it renders.
Now let's look at the rss item viewf.
<fx:Declarations>
<mx:DateFormatter id="myDateFormat" formatString="MMMM D, YYY / L:NN A" />
</fx:Declarations> <fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx"; #titleValue {
font-size: 20px;
font-weight: bold;
}
</fx:Style> <fx:Script>
<![CDATA[ import spark.components.supportClasses.MobileTextField; private function init():void {
//credit to Brian Rinaldi: http://remotesynthesis.com/post.cfm/adding-html-text-to-a-flex-mobile-textarea
MobileTextField(bodyText.textDisplay).htmlText = data.item.description; dateValue.text = myDateFormat.format(data.item.pubDate); }
]]>
</fx:Script> <s:actionContent>
<s:Button height="100%" label="Back" click="navigator.popToFirstView()" />
</s:actionContent> <s:layout>
<s:VerticalLayout paddingTop="10" paddingLeft="5" paddingRight="5" gap="20" />
</s:layout> <s:Label width="100%" id="titleValue" text="{data.item.title}" />
<s:Label width="100%" id="dateValue" /> <s:TextArea id="bodyText" width="100%" height="100%" /> <s:Button width="100%" label="Click to Read" click="navigateToURL(new URLRequest(data.item.link))" />
</s:View>
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="" initialize="init()" xmlns:mx="library://ns.adobe.com/flex/mx">
For the most part, this isn't anything special. Note how I make use of data.item.*. This is the RSS item I passed in with my pushView. Also make note of the button that let's me go back. I don't need this. The hardware itself has a back button. But I like having the obvious button there. Lastly, make note of the nice hack I got from Brian Rinaldi. This is - as far as I know - the only way to display HTML in a mobile component. I'm sure it will be corrected later. Here is how one typical RSS item renders in the application.
And that's it. I've included a zip that includes all the source code. The zip also includes an APK file if you want to skip compiling it yourself. I've got an interesting idea for a follow up to this - and if I can stay off of Warcraft enough - I'll get it out tomorrow night.