Adobe Air Tutorial – Create a Application

December 3, 2008

Practical hands-on Adobe Air Tutorial. This easy to follow series will show you how to use Adobe AIR to create a fully functional Personal Information Management application.

Data-driven Adobe AIR

Relational databases form the core of most data-driven applications. The SQLite database engine is fast, lightweight, and well suited to client-side data management. In this tutorial, I’ll show you how to build data-driven Adobe AIR applications using the SQLite components.

Getting Started

To follow this Adobe AIR tutorial, you’ll need a text editor, and a copy of the Adobe AIR 1.1 SDK (the upcoming 1.5 release should be compatible). A basic understanding of AIR is required.

To start the project, we need a folder to store our code files. I’ll be using C:\AIR\datadriven, and you can substitute this in examples with the path to your project folder. (If the path has spaces, remember to quote it when working in a terminal / command prompt.) Make sure you know the absolute path to bin/adlin your AIR SDK folder – for example, mine’s at C:\AIRSDK\bin\adl.

We’ll be using the jQuery Javascript framework for this application. Grab a copy at jquery.com.

Building the application

We’re going to build a simple Personal Information Management (PIM) utility. The application will simply allow us to create arbitrary “pages” to manage textual information, stored in an in-memory SQL database. An extension of this application could create a complete personal content management system / single-user wiki.

Creating the application descriptor

Open your text editor and create an application.xml file in the project folder. Our application descriptor has a little more detail this time:

<?xml version="1.0" encoding="UTF-8"?> <application xmlns="http://ns.adobe.com/air/application/1.0"> <id>com.example.html.datadriven</id> <version>1.0</version> <filename>datadriven</filename> <description>Data-Driven Adobe AIR Sample</description><initialWindow> <title>Data-Driven Adobe AIR</title> <content>datadriven.html</content> <visible>true</visible> <resizable>false</resizable> <minimizable>false</minimizable> <maximizable>false</maximizable>
		<width>800</width>
		<height>600</height>
		<minSize>800 600</minSize>
	</initialWindow>
</application>

This tells Adobe AIR that we are building an application named “Data-Driven AIR” to be installed in /datadriven. I’ve bolded the additional properties — here’s what they represent:

<description>: this is displayed in the AIR application installer, to explain your app to the user.

<minimizable>, <maximizable>: these control how the user can interact with your initial application window. Keep in mind that any new windows you create (e.g. through Javascript) are not automatically managed with these same guidelines.

<minSize>: this defines an absolute minimum size for your initial application window. The “width height” format is used – no “x”. This is useful to maintain some control if resizing is permitted. Similarly, <maxSize> is available and uses the same format.

Remember, the samples/descriptor-sample.xmlfile in your AIR SDK folder has a full example of the options available.

Creating the HTML framework

We’ll need a fairly basic HTML structure for this application – create datadriven.html with your text editor and copy in the following:

<html> <head> <title>Data-driven AIR Sample</title> <link href="sample.css" rel="stylesheet" type="text/css"/> <script type="text/javascript" src="AIRAliases.js"></script> <script type="text/javascript" src="AIRMenuBuilder.js"></script> <script type="text/javascript" src="jquery-1.2.6.min.js"></script> <script type="text/javascript" src="behaviour.js"></script> </head> <body> <div id="nav"> </div> <div id="body"> </div> </body> </html>

We reference our copy of jQuery (I’m using the minified and gzipped copy of 1.2.6), as well as behaviour.js which will contain our behaviour code. Create this file now, and leave it empty. Also create the sample.cssfile for our CSS styles, and copy in this code:

body { font-family: Tahoma; margin: 0; padding: 0; border: 0; height: 100%; max-height: 100%; } #nav { position: absolute; top: 0; bottom: 0; left: 0; width: 200px; height: 100%; background-color: #eee; padding: 5px; } #body { position: fixed; top: 0; left: 200px; right: 0; bottom: 0; background: #fff; padding: 5px; }

Our references also include the AIRAliases.js file, as well as the menu builder framework AIRMenuBuilder.js. You’ll need to copy both of these from your AIR SDK directory – they’re located under frameworks/ – and place them in your project folder.

We can easily check if this is working so far, using the command line adl utility. Assuming the same paths I mentioned in “Getting Started”, open up a command line window and type the following:

C:\>cd C:\AIR\datadriven C:\AIR\datadriven>C:\AIRSDK\bin\adl.exe application.xml

The application window will appear, with a light-gray navigation pane down the left. We’re all set to start building on AIR!

The Menu System

AIR provides a menu builder framework to make complex menu structures easy. In our last AIR tutorial, we looked at manually constructing AIR menus for power and flexibility. Today, we’re going to use the menu builder framework – in AIRMenuBuilder.js – to make menu creation quick and easy.

With your text editor, create the menus.xml file and copy this in:

<?xml version="1.0" encoding="utf-8"?> <root> <menuitem label="File"> <menuitem label="New Page" onSelect="Menu_createPage" /> <menuitem label="Exit" onSelect="Menu_exit" /> </menuitem> </root>

This XML document represents the structure of our menus. Tree-style data is best represented in some sort of hierarchical format – constructing menus in vanilla Javascript is slightly time consuming to allow for switching contexts. Here, we simply define a menu item, ‘File’, and because our following menu items – ‘New Page’, ‘Exit’ – are within the File node, the menu builder framework will automatically create them as submenu items.

We stil need to create the menu, however. Open up behaviour.js, and copy in the following:

$(document).ready(function(){ $("#body").text('Select a page or create a new one.'); createMenus(); createDB(); populateDB(); refreshPage(); }); function createMenus() { air.ui.Menu.setAsMenu(air.ui.Menu.createFromXML('menus.xml')); }

The first section of this code block points to the various functions we need to construct the page. Using jQuery, any code within a $(document).ready() block is executed once the page DOM has loaded. The createMenus() function instructs the menu builder framework to generate menus from the XML tree in menus.xml, and set that as the standard menu for the application window.

Connecting to a database

AIR allows developers to create an in-memory SQLite database on the fly, for quick and easy data storage. In another tutorial, we’ll look at persisting the database on disk; today, we’ll quickly create a database to store our pages.

At the end of behaviour.js, add the following:

function createDB() { db = new air.SQLConnection(); try { db.open(null); } catch (error) { air.trace('Could not open in-memory DB.'); } } function populateDB() { stmt = new air.SQLStatement(); stmt.sqlConnection = db; stmt.text = "DROP TABLE IF EXISTS pages"; stmt.execute(); stmt.text = "CREATE TABLE pages (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, content TEXT)"; stmt.execute(); }

Here, the createDBfunction tries to establish a new SQL connection, and set the global db variable to the connection handle. This will allow us to conduct operations on this particular database later; AIR is built for multiple synchronous database connections as needed.

The populateDB function proceeds to create our pages table, which will store the titles and content of the various pages in our application. Notice we establish an air.SQLStatement object, and point it to our database connection first. Long-running queries can be run in asynchronous mode to avoid locking up the interface; for now, we’ll just execute our queries immediately.

Listing pages in the menu

Add this code to the end of behaviour.js:

function refreshPage() { stmt.text = "SELECT id,title FROM pages"; stmt.execute(); result = stmt.getResult(); $("#nav").empty(); if (!result.data) return; for(i=0;i<result.data.length;i++) { var row = result.data[i]; $('<a>').attr('href', '#') .text(row.title) .click(function(){viewPage(row.id);}) .appendTo('#nav'); $('#nav').append('<br/>'); } }

This will, whenever requested, print out a fresh list of page titles from the database into our navigation bar. When we run a SQL query and expect results, we can retrieve a result object from air.SQLStatement.getResult(), which has a data property – an array – which in turn has a length property informing us of how many rows are in the result set. We can use this to iterate over result.data, and use the power of jQuery to quickly construct links. Whenever the page link is clicked, we call the viewPage function – so let’s go ahead and define that now.

Add this to the end of behaviour.js:

function viewPage(id) { stmt.text = "SELECT content FROM pages WHERE id = ?"; stmt.parameters[0] = id; stmt.execute(); $("#body").html(stmt.getResult().data[0].content); }

Once again, we query our SQLite database to find the particular page ID requested, and insert its contents into the <div id="body"> on the page.

Creating pages; Menu behaviours

Finally, we need to allow the creation of new pages, to get data into the system. We also need a behaviour for the menu button.

Recall in menus.xml, we referenced the Menus_createPage and Menu_exitfunctions:

<?xml version="1.0" encoding="utf-8"?> <root> <menuitem label="File"> <menuitem label="New Page" onSelect="Menu_createPage" /> <menuitem label="Exit" onSelect="Menu_exit" /> </menuitem> </root>

Let’s define these now in behaviour.js:

function Menu_createPage() { title = prompt('Please enter a page title.'); content = prompt('Enter your page content.'); stmt.clearParameters(); stmt.text = "INSERT INTO pages (title, content) VALUES (?, ?)" stmt.parameters[0] = title; stmt.parameters[1] = content; stmt.execute(); stmt.clearParameters(); refreshPage(); } function Menu_exit() { var event = new air.Event(air.Event.EXITING, false, true); air.NativeApplication.nativeApplication.dispatchEvent(event); if (!event.isDefaultPrevented()) { air.NativeApplication.nativeApplication.exit(); } }

We use the Javascript prompt system to take textual input from the user. AIR displays a full-size text input for our usage. We then use a SQL statement with parameters – the ? question marks in our query represent placeholders, and any data passed in through parameters is sanitized to avoid security issues. We need to remember to clear parameters afterwards, as we share our SQLStatementobject between many SQL queries. Once we have created the new page, we refresh the current page list by calling the refreshPage function.

The exit function is identical to the one we used last time – we check if any other areas of the runtime want to stop exiting at this point, and if not, we go ahead and terminate the application.

Wrapping up

Here’s our completed behaviour.js:

$(document).ready(function(){ $("#body").text('Select a page or create a new one.'); createMenus(); createDB(); populateDB(); refreshPage(); }); function createMenus() { air.ui.Menu.setAsMenu(air.ui.Menu.createFromXML('menus.xml')); } function createDB() { db = new air.SQLConnection(); try { db.open(null); } catch (error) { air.trace('Could not open DB.'); } } function populateDB() { stmt = new air.SQLStatement(); stmt.sqlConnection = db; stmt.text = "DROP TABLE IF EXISTS pages"; stmt.execute(); stmt.text = "CREATE TABLE pages (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, content TEXT)"; stmt.execute(); } function refreshPage() { stmt.text = "SELECT id,title FROM pages"; stmt.execute(); result = stmt.getResult(); $("#nav").empty(); if (!result.data) return; for(i=0;i<result.data.length;i++) { var row = result.data[i]; $('<a>').attr('href', '#') .text(row.title) .click(function(){viewPage(row.id);}) .appendTo('#nav'); $('#nav').append('<br/>'); } } function viewPage(id) { stmt.text = "SELECT content FROM pages WHERE id = ?"; stmt.parameters[0] = id; stmt.execute(); $("#body").html(stmt.getResult().data[0].content); } function Menu_createPage() { title = prompt('Please enter a page title.'); content = prompt('Enter your page content.'); stmt.clearParameters(); stmt.text = "INSERT INTO pages (title, content) VALUES (?, ?)" stmt.parameters[0] = title; stmt.parameters[1] = content; stmt.execute(); stmt.clearParameters(); refreshPage(); } function Menu_exit() { var event = new air.Event(air.Event.EXITING, false, true); air.NativeApplication.nativeApplication.dispatchEvent(event); if (!event.isDefaultPrevented()) { air.NativeApplication.nativeApplication.exit(); } }

Finalising, further reading

And we’re done! We can run the completed application at command line again:

C:\>cd C:\AIR\datadriven C:\AIR\datadriven>C:\AIRSDK\bin\adl.exe application.xml

To explore further, the online documentation for AIR has a number of resources you might find handy:

Entry Filed under: Adobe Air. Tags: , , , .

Leave a Comment

Required

Required, hidden

Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackback this post  |  Subscribe to the comments via RSS Feed


Follow us on Twitter

Categories