创建任何桌面应用程序几乎总是需要在本地存储数据,通过Adobe AIR我们有几下面几个选择,一个是我们能够使用内置的 SQLite 数据库支持,对于少量的数据这是大材小用了。另外一个选择是我们通过把数据转换成XML格式,并写入文件中,问题是,如果我们需要一个对象,不得不写一些解码器来转换这个XML。还有另一个选择是在Adobe AIR中,我们序列化一个对象到byte数组,并且写入文件。
好的,我们可以写一个对象到文件中,我们选择那种呢?有两件事情,首先,作为一个byte数组,数组将是非常小的,有利于节省保存空间。最后,我们通过一个或者两个方法来序列化这个类型对象,并且返回类型对象。所以,我们选择最后一种。
在本教程中,我们将在应用程序关闭的时候把用户的一些偏好数据保存起来,在下次程序打开的时候,并重新读取它。所以,让我们先看看后面将要保存文件的这个对象。
package { [RemoteClass] public class UserPrefs { public var name:String; public var appPosX:Number; public var appPosY:Number; public var appWidth:Number; public var appHeight:Number; } }
嗯,应该看到上面有个与众不同的地方。[RemoteClass]元数据标签。Adobe对这个元标签有一个很好的描述,在下面:
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).
使用这个[RemoteClass]元标签来注册的flex类来保存类型信息。当这个类的对象被序列化的时候使用AMF通讯协议
主要的,我们序列化这个对象的时候,需要这个标签来确定它的类型。并且阅读这个对象的所有人都可以看出它的类型(像 UserPrefs)。
为了保存这个对象到文件中,我们仅仅需要几行代码就可以了。为了处理这个问题,我创建了一个拥有一些静态方法的类。类名为FileSerializer
,将拥有写对象到文件,
读文件到对象的方法。
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(); } } }
在上面你可能注意到这个方法有两个参数。object 和 fname ,第一个是写入文件的对象,第二个是写入文件的文件名。方法的第一行是得一个我们将要写入的文件。
我们首先创建了一个FileStream(文件流),并且打开了这个文件的写操作。然后我们使用方法writeObject写这个对象到文件,然后关闭这个文件流。是的,它确实容易。
现在我们能写一个对象到文件,我们也应该创建一个方法来阅读这个文件。下面是一个完整的FileSerializer
类,我们添加了一个新的方法。
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; } } }
读对象的方法基本遵循同样的流程,除了它从文件读对象的方法readObject,然后关闭流,并返回这个对象。如果不能读取这个文件,或者文件中的数据不正确,readObject将抛出一个error。如果你想处理这里,可以try catch这块。
接下来,让我们看看如何使用它,我们构建一个应用程序,需要记住你最后一次打开它的状态。我们从上面的对象很容易做这样的事情,它甚至可能看起来像下面这样。
<?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>
在上面的代码中,我们检查是否有用户的喜好。在creationComplete 里读取文件。如果我们得到了返回的Object ,然后把它转换为UserPrefs ,然后从文件里更新应用程序的nativeWindow
大小和位置。