Read/Write data with ByteArray

lately I have been refactoring my Adobe AIR App, Audiobooks for children. While doing that I wanted to try to make persisting my data a bit easier.
I always thought of using ByteArray but never actual tried it out. So I did, and it is really simple, fast and developer friendly.

So in my previous apps i have always stored my application data by either reading and writing XML or using a SQLite DB.

For the last 2-3 month I have been learning Xamarin for crossplatform mobile development, so I was reading som very cool blog posts from http://jacksondunstan.com on the differences between ActionScript 3 and C#. Those articles are highly recommended reading!
While reading those articles I somehow stumbled upon another cool article about how you can serialize anything in ActionScript 3 using ByteArray.

I thought that it sounded so cool, and too easy not to try out in my app. So I changed the way Im storing the data to use ByteArray

Now I simply write Typed Objects and easily read them again.
In my app I Am persisting all the Tapes the user has in the app. So whenever changes occur (for example, tape position changed because user listened to the stories) I can say “write” all my tapes, and the information is persisted in a millisecond.

To illustrate it bit in code, here is some parts taken from my app code.


// Persisting Data Using ByteArray
// Sample code taken from my Audiobooks for children AIR App for iOS
//
private var _tapes:Array = []; // of TapeItem's
private var _file:File; // for accessing the "physical" stored file on the device
private var _uuid:String; // Stores a UUID for this user - uses the CASALib StringUtil
// In the constructor I register the Class Alias for my TapeItem Object which is my model Object
// tapes used in the app.
registerClassAlias("TapeItem", TapeItem);

// Somewhere in my launch sequence i want to load up all the users tapes that are
// stored in the saveDataFile.lbfb file on the device.
_file = File.applicationStorageDirectory.resolvePath("saveDataFile.lbfb");

// First I need to check if this file actually has been created before
if(_file.exists)
{
     // If it was, then we can safely go ahead and read its data
     readData();
}
else
{
     // If not, then I want to generate a UUID that will also be stored in the savefile
     // Im using this in my app when talking to google analytics.
     // This will only be generated once per installation of the app.
     _uuid = StringUtil.uuid();

     // In my app I have some free stories and recordable tapes. These are configured
     // the first time the user opens the app.

     ... Code that creates free stories for the user. ( TapeItem's )
     _tapes.push(freeTapeItem1);
     _tapes.push(freeTapeItem2);
     // Now that the free Tapes are configures we can save the data.
     writeData();

}

// Lastly we can tell anyone listening, that app is ready.
dispatchReadyToStart();

The writeData function


// Write's the _tapes, and the _uuid to the file.
private function writeData():void
{
     var ba:ByteArray = new ByteArray();

     ba.writeObject(
     {
          tapes: _tapes,
          uuid: _uuid
     });

     ba.compress();
     var fs:FileStream = new FileStream();
     fs.open(_file, FileMode.WRITE);
     fs.writeBytes(ba, 0, ba.bytesAvailable);
     fs.close();
}

The readData function

// Read the _tapes and the _uuid from the file.
private function readData():void
{
   var ba:ByteArray = new ByteArray();
   var stream:FileStream = new FileStream();
   stream.open(_file, FileMode.READ);
   stream.readBytes(ba, 0, stream.bytesAvailable);
   stream.close();
   ba.uncompress();

   var data:Object = ba.readObject();
   _tapes = data.tapes;
   _uuid = data.uuid;
}

So when ever i need to persist data I will just call the writeData method.

For a very detailed read on how to use ByteArray to serialise anything I recommend that you head over and read the full blog-post.

  • Mike Gowan

    Wow. I never realized you could persist a typed object. This is great!

  • Miguel

    streams should be closed in a catch/finally block for safety

  • bjeld

    @Miguel – thanks for the heads up on the try catch finally!

  • Nemi

    Great. What kind of properties does TapeItem has? Is it only int,Number,String,Array or?

  • bjeld

    @Nemi
    these are the properties of the TapeItem
    public var productIdentifier:String;
    public var localizedTitle:String;
    public var fileName:String;
    public var localizedDescription:String;
    public var position:int;
    public var duration:int;
    public var isRelativePath:Boolean;
    public var isRecordable:Boolean;
    public var isLocked:Boolean;
    public var extension:String;
    public var price:Number;
    public var localizedPrice:String;
    public var isProduct:Boolean;
    public var textures:Array = []; // of textures
    public var path:String;
    public var sortIndex:int;

    • Nemi

      Thanks. All simple types. But I see Array, which type Array has? Object or CustomVO or? I guess Array has same object type and it is not custom class. Cause then you should need another line of registerClassAlias(..) for that custom class. Right?