Simple Notes Application with Flex/Flash Builder 4.5 & 4.6

New:

Added sample code project already converted for Flash Builder 4.6 – Yes, I did this in 4.5 Burrito but I still don’t have 4.5 final. 😦 The changes between versions for this simple application are minor.

Get the source project and rename the file from .doc to .fxp

Original Post:

Last April Adobe released the latest version of Flash Builder. This new version is equipped with Flex 4.5 SDK that now includes support for AIR based mobile applications. We can consider it a cross-platform mobile development release since it includes support for Google’s Android, BlackBerry Tablet OS and Apple’s iOS. This post covers a short tutorial on how to create a simple Notes application that can run on any of the aforementioned platforms.

What do I need? Just download Flash Builder 4.5 from Adobe web site.

1 – Creating a Flex mobile project

With Flash Builder 4.5 running, click on File -> New and choose the Flex Mobile Project option. In the project name field insert Notes and click finish.

Your project should now have two files, the Notes.mxml and the views/NotesHome.mxml.

2 – The application data model

The Notes model is a simple class that stores the title and the message of the note.

package model
{
	import mx.collections.ArrayCollection;
	import mx.core.IUID;
	
	[Bindable]
	public class Note implements IUID
	{
		public var id:int;
		public var title:String;
		public var message:String;
		
		public function get uid(): String {
			return id.toString();
		}
		
		public function set uid(value: String): void {
			id = parseInt(value);
		}
	}
}

The application will make use of the NoteDatabase class to store and load entries from the embedded SQL engine.

 
package model
{
	import flash.data.SQLConnection;
	import flash.data.SQLResult;
	import flash.data.SQLStatement;
	import flash.events.SQLEvent;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	
	import model.Note;
	
	import mx.collections.ArrayCollection;
	
	public class NoteDatabase
	{
		private static var _sqlConnection:SQLConnection;

		public static function get sqlConnection():SQLConnection
		{
			if (_sqlConnection)
				return _sqlConnection;
			openDatabase(File.applicationStorageDirectory.resolvePath("MechdyneNotes.db"));
			return _sqlConnection;
		}

		public static function getNote(id:int):Note
		{
			var sql:String = "SELECT id, title, message FROM notes WHERE id=?";
			var stmt:SQLStatement = new SQLStatement();
			stmt.sqlConnection = sqlConnection;
			stmt.text = sql;
			stmt.parameters[0] = id;
			stmt.execute();
			var result:Array = stmt.getResult().data;
			if (result && result.length == 1)
				return processRow(result[0]);
			else
				return null;
		}

		public static function notes():ArrayCollection
		{
			var noteList:ArrayCollection = new ArrayCollection();
			
			var sql:String = "SELECT id, title, message FROM notes";
			var stmt:SQLStatement = new SQLStatement();
			stmt.sqlConnection = sqlConnection;
			stmt.text = sql;
			stmt.execute();
			var sqlResult:SQLResult = stmt.getResult();
			if (sqlResult) {
				var result:Array = sqlResult.data;
				if (result) {
					for (var index:Number = 0; index < result.length; index++) {
						noteList.addItem(processRow(result[index]));
					}
				}
			}
			return noteList;
		}

		public static function addNote(note:Note):void
		{
			var sql:String = 
				"INSERT INTO notes (title, message) " +
				"VALUES (?,?)";
			var stmt:SQLStatement = new SQLStatement();
			stmt.sqlConnection = sqlConnection;
			stmt.text = sql;
			stmt.parameters[0] = note.title;
			stmt.parameters[1] = note.message;
			stmt.execute();
		}

		public static function deleteNote(note:Note):void
		{
			var sql:String = "DELETE FROM notes WHERE id=?";
			var stmt:SQLStatement = new SQLStatement();
			stmt.sqlConnection = sqlConnection;
			stmt.text = sql;
			stmt.parameters[0] = note.id;
			stmt.execute();
		}

		
		protected static function processRow(o:Object):Note
		{
			var note:Note = new Note();
			note.id = o.id;
			note.title = o.title == null ? "" : o.title;
			note.message = o.message == null ? "" : o.message;
			return note;
		}
		
		public static function openDatabase(file:File):void
		{
			var newDB:Boolean = true;
			if (file.exists)
				newDB = false;
			_sqlConnection = new SQLConnection();
			_sqlConnection.open(file);
			if (newDB)
			{
				createDatabase();
				populateDatabase();
			}
		}
		
		protected static function createDatabase():void
		{
			var sql:String = 
				"CREATE TABLE IF NOT EXISTS notes ( "+
				"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
				"title VARCHAR(50), " +
				"message VARCHAR(200))";
			var stmt:SQLStatement = new SQLStatement();
			stmt.sqlConnection = sqlConnection;
			stmt.text = sql;
			stmt.execute();			
		}
		
		protected static function populateDatabase():void
		{
			var file:File = File.applicationDirectory.resolvePath("assets/notes.xml");
			if (!file.exists) return;
			var stream:FileStream = new FileStream();
			stream.open(file, FileMode.READ);
			var xml:XML = XML(stream.readUTFBytes(stream.bytesAvailable));
			stream.close();
			for each (var n:XML in xml.note)
			{
				var note:Note = new Note();
				note.id = n.id;
				note.title = n.title;
				note.message = n.message;
				addNote(note);
			}
		}
		
	}
}

3 – Understanding the new MobileApplication component

The Notes.mxml is the main entry point for the mobile application that you are about to create. In it you’ll find the following:

<?xml version="1.0" encoding="utf-8"?>
<s:MobileApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
					 xmlns:s="library://ns.adobe.com/flex/spark"
					 firstView="views.NotesHome">
	
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>
	
</s:MobileApplication>

The MobileApplication is the main application component and has the responsibility of handling all the native calls to the underlying mobile OS. In it there’s also the ViewNavigator that works like a stack and has the responsibility of handling the pushing and popping of views. Due to mobile platforms limitations, the current view will be completely destroyed from memory on every ViewNavigator push or pop operation.

4 – Working with views

If you look closer you’ll notice that the MobileApplication firstView property is set to the automatically generated “views.NotesHome” shown bellow.

file:NotesHome.mxml

<?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="Home">
	
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>

</s:View>

The View component is where we’ll place the Spark components for rendering. Each MobileApplication includes support for the application bar that it’s divided into three different parts, the navigation content, the title content and the action content parts. For this application we’ll add two new views, one to add a new note to the list and another to view the full note. For that we’ll also have to add a new action button to the application bar.

file: NotesHome.mxml

<?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="Home">
	
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>
	
	<fx:Script>
		<![CDATA[
			import model.Note;
			import model.NoteDatabase;
			
			import spark.events.IndexChangeEvent;
			
			protected function onAddButtonClicked(event:MouseEvent):void {
				navigator.pushView(AddNoteView);
			}
			
			private function onNoteSelected(event:IndexChangeEvent):void {
				var selectedNote:Note = event.currentTarget.dataProvider[event.newIndex];
				navigator.pushView(NoteView, selectedNote);
			}
			
		]]>
	</fx:Script>
	
	
	<s:actionContent>
		<s:Button label="Add" click="onAddButtonClicked(event)"/>
	</s:actionContent>
	
	<s:List dataProvider="{NoteDatabase.notes()}" change="onNoteSelected(event)"
			left="0" right="0" top="0" bottom="0">
		
		<s:itemRenderer>
			<fx:Component>
				<s:MobileIconItemRenderer labelField="title" messageField="message"/>
			</fx:Component>
		</s:itemRenderer>
	</s:List>
	
</s:View>

In the above code we’ve added a new “Add” button to the action content part of the application button. On click, the action button will use the ViewNavigator to push the AddNoteView to the top of the view stack. The top view is always the one being rendered by the application.

In addition, we’ve also added the List component that with the help of the MobileIconItemRenderer will render some of the note details as an entry in the list. On item click the onNoteSelected method will be called and the currently selected note passed to the NoteView.

5 – Creating Views

To create a new view we right click on the views package, select new -> MXML component. For the name we select AddNoteView and we ensure that it is based on the spark.components.View component. For this component we’ll add two labels and two text inputs components that will allow the user to insert the note details. We’ll also add a Save button to the action content part of the application bar. On save, the note details will be saved on the embedded SQL engine and the ViewNavigator used to pop the current top view from the stack and in turn the previous view will be once again back on the top of the view stack.

file: AddNoteView.mxml

<?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="AddNoteView">
	
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>
	
	<fx:Script>
		<![CDATA[
			import model.Note;
			import model.NoteDatabase;
			
			protected function onSave():void {
				var newNote:Note = new Note();
				newNote.title = titleField.text;
				newNote.message = messageField.text;
				
				NoteDatabase.addNote(newNote);
				
				navigator.popView();
			}
		]]>
	</fx:Script>
	
	<s:actionContent>
		<s:Button label="Save" click="onSave()"/>
	</s:actionContent>
		
	<s:layout>
		<s:VerticalLayout paddingLeft="10" paddingRight="10" paddingTop="10" paddingBottom="10"/>
	</s:layout>
	
	<s:Label text="Title"/>
	<s:TextInput id="titleField" width="100%"/>
	
	<s:Label text="Message"/>
	<s:TextArea id="messageField" width="100%" height="200"/>
	
</s:View>

Repeat the same procedure to create a new view named NoteView and add the code bellow. In it we’ll add a Home button to the navigation content and a Delete button to the action content parts of the application bar. The title content part of the application bar will display the note title. For the message we’ll make usage of a simple label rendered on a blue background.

file: NoteView.mxml

<?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="{data.title}">
	
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>
	
	<fx:Script>
		<![CDATA[
			import model.Note;
			import model.NoteDatabase;
			
			protected function onDeleteButtonClicked(event:MouseEvent):void {
				NoteDatabase.deleteNote(data as Note);
				navigator.popView();
			}
			
			protected function onHomeButtonClicked(event:MouseEvent):void {
				navigator.popView();
			}
		]]>
	</fx:Script>
	
	<s:navigationContent>
		<s:Button label="Home" click="onHomeButtonClicked(event)"/>
	</s:navigationContent>
	
	<s:actionContent>
		<s:Button label="Delete" click="onDeleteButtonClicked(event)"/>
	</s:actionContent>
	
	<s:Group left="20" right="20" top="20" verticalCenter="0">
		
		<s:Rect width="100%" height="100%">
			<s:fill>
				<s:SolidColor color="0x0088FF"/>
			</s:fill>
		</s:Rect>
		
		<s:Label id="messageText" left="20" right="20" top="20" bottom="20"
				 text="{data.message}" textAlign="center" maxDisplayedLines="10"/>
	</s:Group>
	
</s:View>

6 – Conclusion
I’ve run this simple application in both Android and BlackBerry Playbook devices and it worked flawlessly. Flash Builder 4.5 also allows to debug applications as they run on the device. As you play with it you’ll feel the power of Flex 4.5 and I’m fully convinced that it will become a major tool in the mobile developer arsenal.

Advertisements

About CrazyPenguin

Software Engineer
This entry was posted in Uncategorized. Bookmark the permalink.

12 Responses to Simple Notes Application with Flex/Flash Builder 4.5 & 4.6

  1. Emre says:

    How can I download this application

  2. flexfactory says:

    thanks…a great example that people can use and understand easily…well done!

  3. Attila Török says:

    Hi,

    Thanks for the post, it helped really lot! If you have some time, please help me in two things:

    – I would like to update a row with new data if I add a new note with existing title
    – I would like to delete all datas from table

    I’m not a programmer, that’s why you think these are stupid question. 🙂

    Please drop me an email.

    Regards,

    Attila from Hungary

    • CrazyPenguin says:

      Attila,

      Sorry for the late reply… been quite busy over here.

      In short, the demo app uses an embedded SQL database and all you need to do is to use SQL commands to change it for you needs.

      		public static function updateNote(note:Note):void
      		{
      			var sql:String = "UPDATE notes SET title=?, message=? WHERE id=?";
      			var stmt:SQLStatement = new SQLStatement();
      			stmt.sqlConnection = sqlConnection;
      			stmt.text = sql;
      			stmt.parameters[0] = note.title;
      			stmt.parameters[1] = note.message;
      			stmt.parameters[2] = note.id;
      			stmt.execute();
      		}
      
      		public static function dropNotes():void
      		{
      			var sql:String = "DELETE * FROM notes";
      			var stmt:SQLStatement = new SQLStatement();
      			stmt.sqlConnection = sqlConnection;
      			stmt.text = sql;
      			stmt.execute();
      		}
      
      • Jerome says:

        I have been trying to use the AddNoteView.mxml to both add new note or update a selected note using if(id==0) then add new note else update selected note. Please help me on this.
        Thanks

  4. Thank you for your example. I had been looking online for some straight forward examples on how to do this in Flash Builder and SQLite. Aside from the description and implementation of “Note.as” in your example(which was a little confusing… your source code download filled in the holes.

    Thanks Again,


    Darkriderdesign

  5. I have 3 MXML files and two as files (Note.as and NoteDataBase.as) . Note.as gives me an error:
    Description Resource Path Location Type
    A file found in a source-path must have the same package structure ‘views’, as the definition’s package, ‘model’. Note.as /Notes/src/views Unknown Flex Problem

  6. never mind I got it 😀

  7. Another question 😀

    I would like to add an list on another view so I copied the “public static function notes():ArrayCollection” and changed the name of it. Now I get an error saying:
    “1061: call to a possibly undefined method members through a reference with static type class.”

    Any advice on how I can have various lists?

  8. rtilekar12 says:

    What about Apple ios. it not for ios? why. and can we modify file system in IOS in mobile flex!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s