When creating any desktop application there is almost always a time when you need to store data on the computer. Now with Adobe AIR we have several options. One would be that we could use the built-in SQLite database support, for a small amount of data this is overkill. Another option is that we could turn the data into XML and write out to a file, the problem with this is that we we have to write some kind of decoder if we want a typed object. There is yet another option we have in Adobe AIR, we can serialize the object into a byte array and write it out to a file.
Ok, so we can write out an object to a file, what does this buy us? Well, two things really. First, as a byte array the data is going to be really small so we are saving space. Lastly, with a trick or two we can serialize typed objects and get back typed objects.
For this tutorial, we are going to save some user preference data at application close and read it back in the next time the application is opened. So let's take a look at the object we are going to save to file.
1 package
2 {
3 [RemoteClass]
4 public class UserPrefs
5 {
6 public var name:String;
7 public var appPosX:Number;
8 public var appPosY:Number;
9 public var appWidth:Number;
10 public var appHeight:Number;
11 }
12 }
Well, nothing above should look out of the ordinary except maybe one thing - the [RemoteClass]
metadata tag. Adobe has a pretty good description of the RemoteClass tag below.
Use the [RemoteClass] metadata tag to register the class with Flex so that Flex preserves type information when a class instance is serialized by using Action Message Format (AMF).
Basically, we need the tag to make sure that when we serialize the object it will keep its type (in this case UserPrefs
) and then when we read the object back out it knows what type of object it is.
In order to save the objects out to file we just need a few lines of code. To handle this I created a class with a few static functions that can be used. The class, named FileSerializer
, will have functions to write objects to file and read objects from file.
package com.paranoidferret.util
{
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
public class FileSerializer
{
public static function writeObjectToFile(object:Object, fname:String):void
{
var file:File = File.applicationStorageDirectory.resolvePath(fname);
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
fileStream.writeObject(object);
fileStream.close();
}
}
}
Above you will notice that the function takes two parameters, object
and fname
. The first is the object to write out to file and second if the filename to use. the first line of the function gets a handle on the file we are going to write to. We first create a FileStream
and open the file for writing. We then write the object out to the file using the function writeObject
and then close the file stream. Yes, it is really that easy.
Now that we can write the object out to file we should also create a function to read it in. Below we have our complete FileSerializer
class with our new read function added in.
package com.paranoidferret.util
{
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
public class FileSerializer
{
public static function writeObjectToFile(object:Object, fname:String):void
{
var file:File = File.applicationStorageDirectory.resolvePath(fname);
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
fileStream.writeObject(object);
fileStream.close();
}
public static function readObjectFromFile(fname:String):Object
{
var file:File = File.applicationStorageDirectory.resolvePath(fname);
if(file.exists) {
var obj:Object;
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.READ);
obj = fileStream.readObject();
fileStream.close();
return obj;
}
return null;
}
}
}
The read object function basically follows the same flow except it reads the object from the file using the function readObject
. It then closes the stream and returns the object. If the file can not be read or the data in the file is incorrect readObject
will throw an error. You can handle this with a try catch block if you wanted.
Next, let's take a look at how you would use something like this. Say we are building an application which needs to remember where on the screen it was the last time you opened it. With our object from above it is easy to do something like this. It might even look something like the following.
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
width="300" height="200"
creationComplete="init()"
closing="closing()">
<mx:Script>
<![CDATA[
import com.paranoidferret.util.FileSerializer;
private var up:UserPrefs;
private function init():void
{
this.up = FileSerializer.readObjectFromFile("prefs.up") as UserPrefs;
if(up) {
this.nativeWindow.x = up.appPosX;
this.nativeWindow.y = up.appPosY;
this.nativeWindow.width = up.appWidth;
this.nativeWindow.height = up.appHeight;
this.nativeWindow.title = up.name;
} else {
this.up = new UserPrefs();
}
}
private function closing():void
{
this.up.name = "The Fattest";
this.up.appPosX = this.nativeWindow.x;
this.up.appPosY = this.nativeWindow.y;
this.up.appWidth = this.nativeWindow.width;
this.up.appHeight = this.nativeWindow.height;
FileSerializer.writeObjectToFile(this.up, "prefs.up");
}
]]>
</mx:Script>
</mx:WindowedApplication>
In the above code we check if there are user preferences available by reading the file on creationComplete
in our init
function. If we get an object back we cast is as our UserPrefs
object and then update the application nativeWindow
to be the correct size and position. Otherwise we just create a new user preferences object. To save the information back out we hook into the closing
event and write the current size and position back out to our preferences file.
That pretty much wraps it up. I hope this tutorial helps out in some way. At the very least we have learned how easy it is to work with files in AIR. If anyone has any questions as always feel free to leave a comment. I have also included the FileSerializer
class in the source files below.
http://www.switchonthecode.com/tutorials/adobe-air-and-flex-saving-serialized-objects-to-file