back

Learn to build your first desktop application with Adobe Flex 3

by Zach Stepek

With Adobe AIR, developers can leverage existing skill sets with Flash, Flex, HTML, JavaScript, and SQL to create applications that run on the desktop instead of in a web browser. These applications have access to the local file system, can store information in local databases, are able to detect the Internet connection on the local machine, and do much more.

In this article, I show you how to create your first AIR application, an RSS reader, in fewer than 50 lines of code with Flex Builder 3. Strap yourself in, and we'll start our exploration of this amazing new technology.

Note: For the uninitiated, a free 60-day trial of Flex Builder 3 is available.

The application

The application we're building is a simple RSS reader with basic history management (see Figure 1). To create it with fewer than 50 lines of code, we'll work with some code libraries and style sheets that are available online that will save us some work and development time. To begin, download the XML Syndication Library and Shadow CSS style sheet.

An Adobe AIR RSS reader.

Figure 1. An Adobe AIR RSS reader.

Laying the foundation

To get this project set up and to lay out the application, create a new project in Flex Builder:

  1. Choose File > New > Flex Project.
  2. Name your project AiRSS Reader, and set the application type to Desktop application (which runs in Adobe AIR). You don't need to select a server type for this application. Click Next.
  3. Keep the output folder set to the default of bin-debug, and click Next.
  4. Assign a unique ID to your application. We'll use reverse domain notation to do this, which ensures a unique ID by incorporating your domain name into the application ID. For this project, I'm using com.adobe.edge.august2008.AiRSS as the application ID.
  5. Click Finish, and you will see your empty application file.

Figure 2 shows the schematic we're using to develop the AiRSS user interface. The interface is divided into three logical sections: navigation, article list, and article detail. The navigation section houses five elements: forward and back buttons, an address bar, a submit button, and a bookmark button. The article list section is simply a data grid component that shows a list of articles available at the current location. The article detail section is an HTML control and uses some automatically generated HTML to show article details.

The schematic for the AiRSS application.

Figure 2. The schematic for the AiRSS application.

The HTML control is new to AIR and is available in any Flex 3 application that targets the AIR runtime. The control is not available for Flex applications that target the browser. The control embeds a full version of the WebKit HTML rendering engine, the same engine used in Apple's Safari browser, in your AIR application.

To create a flexible user interface for this application that enables users to resize the article list and detail sections to their desired height, use the VDividedBox to lay out the main section of your application (see Figure 3). There are two items inside the VDividedBox: a DataGrid control to show the list of articles available in the RSS feed and an HTML control to show the details of the currently selected article in the DataGrid.

A diagram of the AiRSS layout.

Figure 3. A diagram of the AiRSS layout.

To begin building the application in MXML:

  1. Add an ApplicationControlBar tag block inside the WindowedApplication tag block. Give this tag a dock property of true. This ApplicationControlBar houses all the application navigation. It is docked at the top of the application, is stretched to be the full width of the application, and is outside the scrollable area of the application.
  2. Inside that tag block, add two Button tags. Set their ID properties to btnPrev and btnNext. Set their label properties to < and >, respectively.
  3. Add a Label tag, and set the text property to Feed URL:.
  4. After the label, insert a TextInput tag with an ID of txtFeedURL.
  5. Add another Button tag with a label of Get Feed and an ID of btnGetFeed. This button is used to get the RSS feed from the remote server when it is clicked.

Your code should look like the following:

    <mx:WindowedApplication>
        <mx:ApplicationControlBar width="100%" dock="true">
            <mx:Button id="btnPrev" label="&lt;"/>
            <mx:Button id="btnNext" label="&gt;"/>
            <mx:Label text="Feed URL:"/>
            <mx:TextInput id="txtFeedURL" width="100%"/>
            <mx:Button id="btnGetFeed" label="Get Feed"/>
        </mx:ApplicationControlBar>
    </mx:WindowedApplication>
    

Now it's time to add the DataGrid and HTML control, to finish the layout of the application:

  1. Add a VDividedBox tag block under the ApplicationControlBar. Give it left, right, top, and bottom properties with a value of 10 pixels.
  2. Inside the VDividedBox tag block, add an empty DataGrid tag block with an ID of feedList and a width and height of 100%.
  3. After the DataGrid, add an HTML tag with an ID of feedDetail and a width and height of 100%.

Your code should now look like this:

    <mx:WindowedApplication>
        <mx:ApplicationControlBar width="100%" dock="true">
            <mx:Button id="btnPrev" label="&lt;"/>
            <mx:Button id="btnNext" label="&gt;"/>
            <mx:Label text="Feed URL:"/>
            <mx:TextInput id="txtFeedURL" width="100%"/>
            <mx:Button id="btnGetFeed" label="Get Feed"/>
        </mx:ApplicationControlBar>
        <mx:VDividedBox width="100%" height="100%">
            <mx:DataGrid id="feedList" width="100%" height="100%">
            </mx:DataGrid>
            <mx:HTML id="feedDetail" width="100%" height="100%"/>
        </mx:VDividedBox >
    </mx:WindowedApplication>

Syndication made simple

You have set the stage for your project by laying out the application. Now, it's time to add RSS data into your reader. As I mentioned earlier, we're going to use the XML Syndication Library to simplify the RSS parsing. This library is part of the ActionScript 3.0 Library Project on Google Code. The purpose of the library is to parse any RSS feed into a generic RSS object so you can work with RSS 0.9, RSS 1.0, RSS 2.0, and ATOM with the same syntax. This greatly simplifies your application because the library does the majority of the heavy lifting.

To add the library to your project, you need to add the SWC file that you downloaded to the Library Path for the project:

  1. Open your project properties, and select Flex Build Path.
  2. In the Library Path tab, click the Add SWC button and then navigate to the library file. Choose the as3syndication.swc file and click OK.
  3. Click OK again to confirm your changes.

Feeding the reader

For your application to ingest your RSS feed and then handle the result, you need to complete a few more steps. First create an HTTPService tag, which will request the remote feed. Give this tag an ID of feedService so you can refer to it with ActionScript later if you need to. Next, set the resultFormat of the HTTPService tag to E4X. This prevents the default behavior of converting ingested XML into an object. Finally, add a reference to a result handler, which you will create later, by setting the result property equal to feedHandler(event). This sends the result from the HTTPService call to the feedHandler method when it is received by the application. The current HTTPService tag looks like this:

<mx:HTTPService id="feedService" resultFormat="e4x" result="feedResult(event)" />

Next, you need to create a method to handle the result from your HTTPService. Create a script block under the opening WindowedApplication tag. In this tag block, add the following import statements:

   import com.adobe.xml.syndication.generic.IFeed;
   import com.adobe.xml.syndication.generic.FeedFactory;
   import mx.collections.ArrayCollection;
   import mx.rpc.events.ResultEvent;

After your imports are added, you need to declare a couple of variables that you'll be using in your result handler. After the import statements, add a bindable private ArrayCollection named feedItems. Then create a bindable private IFeed instance named RSSFeed. To declare an item as bindable, simply add a [Bindable] metadata before the variable declaration. This tells the compiler to build an event model around that variable that updates anything that is listening for changes or bound to that item. The binding listeners are defined using curly braces, for example, {variableName}.

Finally, it's time to create your feedHandler method. Create feedHandler as a private method accepting a parameter of event typed as a ResultEvent and with a return type of void. In this method, you need to create a local XML variable named feedResult. This variable will store the RSS result that comes in from your HTTPService request. You will then use this variable with the FeedFactory from the XML syndication library to give a value to your RSSFeed variable. Finally, you'll set your FeedItems ArrayCollection to RSSFeed.items, which is the repeating item in your feed. This will be used to populate your DataGrid with the items in the feed. When you've finished all of this, your script tag block should look like this:

   <mx:Script>
   <![CDATA[
      import com.adobe.xml.syndication.generic.IFeed;
      import com.adobe.xml.syndication.generic.FeedFactory;
      import mx.collections.ArrayCollection;
      import mx.rpc.events.ResultEvent;
         
      [Bindable]
      private var feedItems:ArrayCollection;
         
      [Bindable]
      private var RSSFeed:IFeed;
         
      private function feedResult(event:ResultEvent):void {
         var feedResult:XML = new XML(event.result);
         RSSFeed = FeedFactory.getFeedByXML(feedResult);
         feedItems = new ArrayCollection(RSSFeed.items);
      }
   ]]>
   </mx:Script>

Wiring it all together

So, you've done the hardest part, which is to bring your RSS feed into your application. Now, you just have to wire everything together using Flex bindings to show your feed items in your DataGrid and to show the currently selected item's excerpt in your HTML control. Also, to get it all to work, you need to bind the feedURL TextInput to the URL property of your HTTPService tag and then trigger the call to the remote service using the send() method of HTTPService.

Start by binding the feedItems ArrayCollection to your DataGrid. To do this, simply add a dataProvider property to your DataGrid that is bound to feedItems. This will populate the DataGrid with all of the properties of the item, however, and you probably don't need all that information about the feed. So you'll want to use some DataGridColumns to restrict the visible columns. You need columns for at least date and title, so add those to your DataGrid tag block. The complete DataGrid tag block should look like this:

<mx:DataGrid id="feedList" dataProvider="{feedItems}" width="100%" height="100%">
    <mx:columns>
        <mx:DataGridColumn dataField="date" headerText="Date"/>
        <mx:DataGridColumn dataField="title" headerText="Title"/>
    </mx:columns>
</mx:DataGrid>

Now that your DataGrid is ready to receive your data, you need to get the HTTPService ready to request it. The first thing you need to do is add a URL property to HTTPService that is bound to feedURL.text. Then, trigger your feedService.send() method on two events, click the Get Feed button, and enter the feedURL TextInput. When you're finished, your HTTPService tag should resemble this:

<mx:HTTPService id="feedService" url="{feedURL.text}" resultFormat="e4x" result="feedResult(event)"/>

The button and TextInput should look like this:

<mx:TextInput id="feedURL" width="100%" enter="feedService.send()" />
<mx:Button label="Get Feed" click="feedService.send()"/>

You're almost there. The last thing to do before you add some cosmetic polish is bind the excerpt of the currently selected item in the DataGrid to the HTML control. Simply add an htmlText property bound to the value of feedList.selectedItem.excerpt.value. The final HTML control is shown here:

<mx:HTML id="feedDetail" width="100%" height="100%" htmlText="{feedList.selectedItem.excerpt.value}"/>

Go ahead and run the application as it is. Functionally, the application is finished. To test it, I suggest that you use the Google News feed. Click an item in the DataGrid once the feed has loaded, and it will show the excerpt in the HTML control. Then, click a link or the Play button in an embedded video, and you'll see that you have actually created a pretty powerful application.

If you are adventurous, you will now do your best to break the application. Let me save you some trouble; it's easy to break. In the interest of keeping things simple, you don't have several of the things that would be built into a production application, such as proper error handling or field validation. This is an example that has been engineered to be as small as possible, so some things are excluded.

A little bit of history

So, you have a web browser built into your application, and you have buttons that look like Back and Forward buttons, but they don't do anything yet. It's really easy to add simple history management to your HTML control. In fact, you can do it with just two method calls: feedDetail.historyBack() and feedDetail.historyForward(). I've included the changes below:

<mx:Button label="&lt;" click="feedDetail.historyBack()"/>
<mx:Button label="&gt;" click="feedDetail.historyForward()"/>

Adding some style

I'm never content to leave a Flex application with the default Flex look and feel, so I'll show you how to import a simple style sheet into your application. Earlier, you downloaded the shadow.css file from ScaleNine and placed the file in the root of your project. You can now import it into your application.

Below the script block, add a Style tag that points to the shadow.css file. It's really that simple. It should look like this:

<mx:Style source="shadow.css"/>

A bird's eye (re)view

Adobe AIR is awesome. It enables you to utilize existing skills to build desktop applications, and it makes building them fun. Now that you've built your first Adobe AIR application, here are a few takeaways that I hope you'll keep in mind for future applications.

Prebuilt ActionScript 3.0 libraries can significantly save you time. By using the existing ActionScript 3.0 Syndication libraries, you were able to build your entire RSS reader with fewer than 50 lines of code. Whenever possible, try to leverage the great open source community for Adobe products. One of my favorite open source resources is RIAForge.

HTML in AIR opens up many possibilities for your applications. You built a fairly complex application, but you were able to do so rather simply because you have the full WebKit rendering engine available in the Adobe AIR runtime.

Applications don't have to be huge to be useful. When you're starting a project, distill it down to the essence of what you're trying to accomplish, and build that first. When you do that, you're focusing on the core use case for your application first. You can always add other bells and whistles later.

Desktop development doesn't need to be hard. In fact, it can be fun. Rather than having to know C#, Objective-C, and any number of other libraries to be a cross-platform developer, you can use the agility of Flex with the power of the Flash platform and the Adobe AIR runtime to build complex applications rapidly.

Take a look at the full AiRSS application code:

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
        <![CDATA[
            import mx.rpc.events.ResultEvent;
            import com.adobe.xml.syndication.generic.IFeed;
            import com.adobe.xml.syndication.generic.FeedFactory;
            import mx.collections.ArrayCollection;
            
            [Bindable]
            private var feedItems:ArrayCollection;
            
            [Bindable]
            private var RSSFeed:IFeed;
            
            private function feedResult(event:ResultEvent):void {
                var feedResult:XML = new XML(event.result);
                RSSFeed = FeedFactory.getFeedByXML(feedResult);
                feedItems = new ArrayCollection(RSSFeed.items);
            }
        ]]>
    </mx:Script>
    
    <mx:Style source="shadow.css"/>
    
    <mx:HTTPService id="feedService" url="{feedURL.text}" resultFormat="e4x" 
        result="feedResult(event)"/>
    
    <mx:ApplicationControlBar dock="true" width="100%">
        <mx:Button label="&lt;" click="feedDetail.historyBack()"/>
        <mx:Button label="&gt;" click="feedDetail.historyForward()"/>
        <mx:Label text="Feed URL: "/>
        <mx:TextInput id="feedURL" width="100%" enter="feedService.send()" />
        <mx:Button label="Get Feed" click="feedService.send()"/>
    </mx:ApplicationControlBar>
    <mx:VDividedBox width="100%" height="100%">
        <mx:DataGrid id="feedList" width="100%" height="100%"
                         dataProvider="{feedItems}">
            <mx:columns>
                <mx:DataGridColumn dataField="date" headerText="Date"/>
                <mx:DataGridColumn dataField="title" headerText="Title"/>
            </mx:columns>
        </mx:DataGrid>
        <mx:HTML id="feedDetail" width="100%" height="100%"
                    htmlText="{feedList.selectedItem.excerpt.value}"/>
    </mx:VDividedBox>
</mx:WindowedApplication>

Where to go from here

We've reached the end of our journey together into the world of Adobe AIR possibilities. However, we certainly haven't explored everything that can be accomplished with Flex and AIR. Take a look at some of the articles in the Adobe AIR Developer Center, read one of the great books on developing AIR applications with Flex, or find a training provider near you and take the "AIR: Building Desktop Applications with Flex 3" course. Some excellent sample AIR applications are already available. Many are listed on the Adobe AIR Marketplace. In addition, Adobe Media Player is built on Adobe AIR.

I hope this article encourages you to start your own exploration into this new world. If you need it, Figure 5 shows the finished application. Have fun while you learn to leverage everything else AIR has to offer, and feel free to share your creations with me at zach@cravemg.com.

 

‹ Back


Zach Stepek is an Adobe Community Expert for RIAs, an Adobe Certified Instructor for Flex and Adobe AIR, and founder and manager of the Stateline Adobe User Group in Rockford, Illinois. His company, Crave Media Group, creates RIAs and rich media experiences built on Adobe technologies and is an Adobe Authorized Training Center. Stepek is also one of the founders of RIApalooza, a platform-agnostic mini-conference about the business of RIAs that debuted May 2008 in Chicago and should find its way to other midwest cities (USA) in the near future.