完全手册——Flex3.0 RIA开发详解:基于ActionScript3.0实现(含光盘)
当前章节: Flex3.0新特性的应用
Flex 3.0中最大的变化在于新增AIR工程。AIR应用程序是一种桌面应用程序。因为要支持对本地资源的操作,所以Flex 3.0中新增许多对本地资源的操作,如本地文件、PDF文件等。另外,AIR应用程序支持版本升级、集成网页、使用Ajax技术等。本章将介绍Flex 3.0这些新特性的具体应用。
23.1 加载PDF文件
在Flex 3.0中的AIR工程中新增HTMLControl类和HTMLPDFCapability类。通过这两个类可实现加载PDF文件,丰富了AIR应用程序的效果和功能。本小节将为读者介绍如何在AIR工程中加载PDF文件。
23.1.1 加载PDF文件前的准备
加载PDF文件需要有两个条件:第一是必须为AIR工程,第二是系统已安装Adobe Reader 8.1以上版本。前者是因为Flex 3.0中只有在AIR工程中可引用HTMLControl类和HTMLPDFCapability类。究其深层原因是Adobe公司只允许桌面应用程序(AIR)访问本地资源。其他Web工程出于安全性考虑,不可直接访问本地资源。
23.1.2 使用HTMLControl类加载PDF文件
HTMLControl类是AIR中新增的类,用于加载PDF。使用HTMLControl类加载PDF文件的语法如下所示。
HTMLControl变量.load(URLRequest变量);
以下代码使用HTMLControl类加载“123.pdf”文件。
var t:URLRequest=new URLRequest("123.pdf");
var hc:HTMLControl=new HTMLControl();
hc.load(t);
HTMLControl类中只有一个属性pdfCapability。此属性存储了PDF文件与Adobe Reader版本间的关系。在HTMLControl类的load方法执行后,自动得到版本信息。
23.1.3 使用HTMLPDFCapability类检测Adobe Reader版本
HTMLPDFCapability类定义了加载的PDF文件与Adobe Reader版本间的关系,使用状态字符串表示,如“ERROR_INSTALLED_READER_NOT_FOUND”。HTMLPDFCapability类的状态字符串如表23-1所示。
表23-1 HTMLPDFCapability类的状态字符串
|
状 态 名 |
说 明 |
|
HTMLPDFCapability.STATUS_OK |
系统中已安装Adobe Reader 8.1以上版本 |
|
HTMLPDFCapability.ERROR_INSTALLED_READER_NOT_FOUND |
系统中未安装Adobe Reader |
|
HTMLPDFCapability.ERROR_INSTALLED_READER_TOO_OLD |
系统中Adobe Reader版本太旧 |
|
HTMLPDFCapability.ERROR_PREFERRED_READER_TOO_OLD |
当前有旧的Adobe Reader版本正在读取PDF |
使用HTMLControl类的pdfCapability属性和HTMLPDFCapability类的状态字符串就能确定PDF文件与Adobe Reader版本间的关系。
以下代码表示系统中已安装Adobe Reader 8.1以上版本,可正常加载的PDF文件。
if(ht.pdfCapability==HTMLPDFCapability.STATUS_OK)
{
Alert.show("加载PDF正常");
}
23.1.4 加载PDF文件实例
加载PDF文件的步骤如下所示。
新建AIR工程。
确定系统中已安装Adobe Reader 8.1以上版本。
编写MXML文件。
MXML程序中主要处理是在初始化应用程序时加载PDF文件,并将结果添加到<mx:HTML>组件。以下代码加载PDF文件“1.pdf”并显示于<mx:HTML>组件上。
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplicationxmlns:mx="http://www.adobe.com/2006/mxml"layout="absolute"creationComplete="initApp()">
<mx:Script>
<![CDATA[
import flash.html.HTMLPDFCapability; //引用HTMLPDFCapability类
import flash.html.HTMLControl; //引用HTMLControl类
import mx.controls.Alert; //引用Alert类
//应用程序初始化函数
private function initApp():void
{
//Adobe Reader 8.1版本以上已安装时,加载pdf
if(HTMLControl.pdfCapability==HTMLPDFCapability.STATUS_OK)
{
var request:URLRequest = new URLRequest("1.pdf");//定义URLRequest实例
var pdf:HTMLControl = new HTMLControl(); //定义HTML
Control实例
pdf.height = 800; //设置pdf高度
pdf.width = 600; //设置pdf宽度
pdf.load(request); //加载pdf
container.addChild(pdf); //将pdf添加到HTML组件上
}
else
Alert.show("pdf不能显示,请安装Adobe Reader 8.1以上版本");
}
]]>
</mx:Script>
<mx:HTML id="container"/>
</mx:WindowedApplication>
(33) “if(HTMLControl.pdfCapability==HTMLPDFCapability.STATUS_OK)”语句用以判断系统中是否安装Adobe Reader 8.1以上版本。若未安装,则加载PDF文件不能完成。
(34) PDF文件只能显示于<mx:HTML>组件中。“container.addChild(pdf);”语句表示在<mx:HTML>组件中添加PDF文件数据。
按下Ctrl+F11键,编译运行程序。运行效果如图23-1所示。

图23-1 加载PDF文件效果
23.2 使用本地SQL数据库
SQL数据库是指可使用标准的SQL语句进行操作的数据库。本地SQL数据库是指操作系统支持的SQL数据库,如“.db”格式的数据库。AIR应用程序中新增了一些类(在“flash.data.*”包中),用以支持对本地SQL数据库的操作。对SQL数据库的基本操作包括Select(读取数据)、Insert(插入数据)、Update(修改数据)、Delete(删除数据)。本章将介绍对SQL数据库操作的基本语句及如何使用新增类操作数据库。
23.2.1 使用Select语句读取数据
Select语句用以读取表中的数据,其语法如下所示。
Select 列名1[as 别名1],列名2[as 别名2],…,列名n[as 别名n] from表名 where 条件
(35) 列名是指表中的列的名称。
(36) 用户可为列名取别名。此项默认与列名相同。
(37) 条件是指对数据的约束。例如,取表中考试成绩不及格的学生信息。
以下代码从学生成绩表“StudentScore”中读取不及格学生的学号、姓名、班级、成绩。
Select studentId as 学号,studentName as 姓名,studentClass as 班级,score as 成绩 from StudentScore where score<60
若读取表中的全部数据列,可使用“*”符。
若上述“StudentScore”表中只有学号、姓名、班级、成绩四列,读取数据的代码可如下所示。
Select * from StudentScore where score<60
23.2.2
使用Insert语句添加数据
Insert语句用以向表中添加数据,其语法如下所示。
Insert into 表名(列名1,列名2,...,列名n) values (数值1,数值2,…数值n)
(38) 列名必须是表中存在的列的名称。
(39) 数值顺序对应列名顺序,如数值1赋值给列名1。
以下代码向学生成绩表“StudentScore”中添加一条数据。
Insert into StudentScore(studentId,studentName,score) values (‘08’,’小明’,77)
对于字符串数据使用单引号封闭,数值不需要单引号封闭。
上述语法可选择性地添加列数据。例如,表中有四列,但只添加其中三列的数据。若对全部列添加数据可省略列名,其语法如下所示。
Insert into 表名 values (数值1,数值2,…数值n)
数值顺序必须严格遵循表中列的顺序。数值个数必须与列的个数相同。
以下代码向学生成绩表“StudentScore”中添加一条完整数据。
Insert into StudentScore values (‘08’,’小明’,’高三5班’,77)
23.2.3
使用Update语句修改数据
Update语句用以修改表中的数据,其语法如下所示。
Update 表名 set 列名1=修改值1,列名2=修改值2,…,列名n=修改值n where 条件
Update可修改表中的单条记录或多条记录。使用条件语句来控制修改范围。
以下代码使用Update语句将成绩59分修改为60分(及格)。
Update StudentScore set score=60 where score=59
需要注意的是,SQL语句中判断相等的操作符为“=”,而不是“==”。赋值语句使用Set子句或Select子句(Select语句的另外一种用法)。
若用户只想修改单条记录,可定义更加严格的条件。以下代码将小明同学的成绩59分提高到60分。
Update StudentScore set score=60 where score=59 and studentName=’小明’
23.2.4
使用Delete语句删除数据
Delete语句用以删除表中的数据,其语法如下所示。
Delete from表名 where 条件
Delete语句可删除单条记录或多条记录,方法是控制条件范围。以下代码使用Delete语句删除“高三5班”学生信息。
Delete from StudentScore where studentClass=’高三5班’
以下代码删除学号为“08”的学生信息。
Delete from StudentScore where studentId=’08’
23.2.5
使用SQLConnection类连接数据库
SQLConnection类用于连接数据库。对于要操作的数据库都应新建SQLConnection类实例。其语法如下所示。
var SQLConnection变量: SQLConnection=new SQLConnection();
以下代码定义了一个SQLConnection实例conn。
var conn:SQLConnection=new SQLConnection();
使用SQLConnection类的“open”方法打开数据库连接。其语法如下所示。
SQLConnection变量.open(File变量);
以下代码使用open方法打开本地SQL数据库“School.db”。
var conn:SQLConnection=new SQLConnection();
var dbFile:File =File.applicationResourceDirectory.resolve("School.db");
conn.open(dbFile);
(40) “File.applicationResourceDirectory”语句表示工程资源路径,即“bin”文件夹路径。
(41) resolve方法用以扩展文件路径,可看作是“\”符。
23.2.6 使用SQLStatement类执行SQL语句
SQLStatement类用于执行SQL语句,是操作SQL数据库的重要类。使用SQLStatement类的步骤如下。
定义SQLStatement类实例,其语法如下所示。
var SQLStatement变量:SQLStatement=new SQLStatement();
以下代码定义了一个SQLStatement类实例sqlcmd。
var sqlcmd:SQLStatement=new SQLStatement();
指向其使用的数据库。SQLStatement实例必须指明应用的数据库,即指向SQLConnection实例。SQLStatement实例指向数据库的语法如下所示。
SQLStatement变量.sqlConnection=SQLConnection变量;
sqlConnection属性类型为SQLConnection,表示指向的数据库实例。以下代码中SQLStatement实例stmt指向数据库实例conn。
var conn:SQLConnection=new Connection();
var dbFile:File = File.applicationResourceDirectory.resolve("School.db");
conn.open(dbFile);
var stmt:SQLStatement=new SQLStatement();
stmt.sqlConnection=conn;
为SQLStatement实例定义SQL语句。其语法如下所示。
SQLStatement变量.text="SQL语句";
text属性类型为String,用于定义SQL语句。以下代码为SQLStatement实例stmt定义SQL语句“select * from table”。
var stmt:SQLStatement=new SQLStatement();
stmt.text="select * from table";
执行SQLStatement实例。执行SQLStatement实例的结果是执行SQL语句。使用SQLStatement类的excute方法开始执行SQL语句。其语法如下所示。
SQLStatement变量.excute();
以下代码使用excute方法开始执行SQL语句“select * from table”。
var stmt:SQLStatement=new SQLStatement();
stmt.text="select * from table";
stmt.excute();
为SQLStatement实例添加监听。执行SQLStatement实例后的状态有很多,常用的是正常返回结果和运行异常两种。需要对两个状态都添加监听。为SQLStatement实例添加监听的语法如下所示。
SQLStatement变量.addEventListener(监听状态,处理函数);
以下代码为“SQLEvent.RESULT”(正常返回结果)和“SQLErrorEvent.ERROR”(运行异常)状态添加监听。
stmt.addEventListener(SQLEvent.RESULT,showDataResult);
stmt.addEventListener(SQLErrorEvent.ERROR, errorHandle);
(42) SQLEvent.RESULT状态表示SQLStatement实例执行成功并返回结果。
(43) SQLErrorEvent.ERROR状态表示SQLStatement实例执行异常。
获取返回数据集。执行有返回数据的SQL语句,数据集存储于SQLStatement实例中。使用SQLStatement类的getResult方法可得到数据集。其语法如下所示。
SQLStatement变量.getResult().data;
以下代码使用getResult方法获得SQL语句“select * from table”的执行结果。
var stmt:SQLStatement=new SQLStatement();
stmt.text="select * from table";
stmt.excute(); //执行SQL语句
stmt.addEventListener(SQLEvent.RESULT,showDataResult);
…
function showDataResult(e:SQLEvent):void
{
var t:Array=stmt.getResult().data as Array; //获得结果集
}
23.2.7
操作本地SQL数据库实例
本小节以实例为读者讲解如何使用SQL语句操作数据库,其步骤如下所示。
设计数据库“School”。“School”数据库中只有一张表“Notes”,用以存储通知信息。“Notes”表的列设计如表23-2所示。
表23-2 “Notes”表的设计说明
|
列 名 |
类 型 |
说 明 |
是否为主码 |
|
noteId |
integer |
通知id |
是 |
|
title |
text |
标题 |
|
|
content |
text |
内容 |
|
|
publisher |
text |
发布者 |
|
以下代码是创建表的SQL语句。
CREATE TABLE IF NOT EXISTS Notes
(
noteId INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,
content TEXT,
publisher TEXT,
)
(44) 此SQL语句在应用程序中定义并执行。
(45) “IF NOT EXISTS Notes”语句表示创建表“Notes”前先判断是否已存在此表。若已存在“Notes”表,不执行此创建语句。
(46) “noteId INTEGER PRIMARY KEY AUTOINCREMENT”表示“noteId”列为interger型(整型)、主码、新增记录时自动增1。
新建AIR工程。
设计应用程序的外观模型。
此实例包括一个DataGrid组件,用以绑定数据。一些输入框及按钮,为数据插入数据库作准备。以下代码是外观模型生成的MXML代码。
<mx:Panel >
<mx:DataGrid id="dg" verticalScrollPolicy="auto">
<mx:columns>
<mx:DataGridColumn headerText="编号" dataField="noteId"/>
<mx:DataGridColumn headerText="标题" dataField="title"/>
<mx:DataGridColumn headerText="内容" dataField="content"/>
<mx:DataGridColumn headerText="发布者" dataField="publisher"/>
</mx:columns>
</mx:DataGrid>
<mx:Canvas height="259" width="401">
<mx:Label text="标题" x="10" y="12"/>
<mx:TextInput x="69" y="10" width="296" id="txtTitle"/>
<mx:Label text="内容" x="10" y="51"/>
<mx:TextArea x="69" y="50" width="296" height="110" id="txtContent"/>
<mx:Label text="发布者" x="10" y="171"/>
<mx:TextInput width="92" id="txtPublisher" x="69" y="169"/>
<mx:Button label="确定" id="btnOk" click="insertDataHandle();" x="69" y="218"/>
</mx:Canvas>
</mx:Panel>
设计模式下的外观模型效果如图23-2所示。

图23-2 操作SQL数据库实例的外观效果
连接“School”数据库。本实例中在工程“bin”文件夹下创建“School.db”数据库,并使用SQLConnection类连接数据库。以下代码创建“School.db”数据库,并使用SQLConnection类连接。
private var conn:SQLConnection = new SQLConnection(); //定义SQLConnection实例
private var dbFile:File = File.applicationResourceDirectory.resolve ("School.db"); //定义数据库文件路径
…
conn.open(dbFile); //打开数据库文件
File类中的resolve方法用以定位文件。若指定路径下的文件不存在将自动创建。
创建“Notes”表。在连接数据库“School.db”后,创建“Notes”表。方法是使用SQL语句创建。以下代码使用SQLStatement类执行SQL语句,从而创建“Notes”表。
private var createStmt:SQLStatement=new SQLStatement();//定义SQLStatement实例
//数据库文件打开后的处理函数
private function openHandler(e:SQLEvent):void
{
createStmt.sqlConnection = conn; //定义语句连接的数据库
//sql语句创建表Notes
var sql:String ="CREATE TABLE IF NOT EXISTS Notes ("
+"noteId INTEGER PRIMARY KEY AUTOINCREMENT,"
+"title TEXT,"
+"content TEXT,"
+"publisher TEXT"
+")";
createStmt.text = sql;
createStmt.execute(); //执行sql语句
}
获得数据集并显示于DataGrid组件中。在执行完创建表的SQL语句后,使用Select语句获取“Notes”表中的全部数据,并绑定至DataGrid组件上。以下代码使用SQLStatement实例createStmt执行Select语句,从而获得“Notes”表中的数据,并显示于DataGrid组件。
//创建完表或已存在表时显示表中的数据
private function createTableResult(e:SQLEvent):void
{
createStmt.sqlConnection = conn; //定义语句连接的数据库
createStmt.text ="select * from Notes";
//添加对SQLEvent.RESULT状态的监听
createStmt.addEventListener(SQLEvent.RESULT,showDataResult);
createStmt.execute(); //执行sql语句
}
//显示数据处理函数
private function showDataResult(event:SQLEvent):void
{
dg.dataProvider=createStmt.getResult().data; //绑定数据集
}
向数据库中插入数据。当单击“确定”按钮时,使用Insert语句将数据插入到数据库中。以下代码使用SQLStatement实例stmt执行Insert语句,从而向“Notes”表中插入新数据。
//插入数据处理函数
private function insertDataHandle():void
{
var stmt:SQLStatement=new SQLStatement();
stmt.sqlConnection = conn; //定义语句连接的数据库
stmt.text ="insert into Notes(title,content,publisher) values('"
+txtTitle.text+"','"
+txtContent.text+"','"
+txtPublisher.text+"')";
stmt.execute(); //执行sql语句
}
完成剩余代码。应用程序剩余的代码包括初始化函数initApp、运行异常处理函数errorHandle、引用不同类等。
以下是应用程序的完整代码。
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication width="600"
fontSize="13" height="500"
xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete ="initApp()">
<mx:Script>
<![CDATA[
import flash.data.SQLConnection; //引用SQLConnection类
import flash.data.SQLStatement; //引用SQLStatement类
import flash.events.SQLErrorEvent; //引用SQLErrorEvent类
import flash.events.SQLEvent; //引用SQLEvent类
import flash.filesystem.File; //引用File类
import mx.controls.Alert; //引用Alert类
private var conn:SQLConnection = new SQLConnection(); //定义SQLConnection实例
private var createStmt:SQLStatement=new SQLStatement(); //定义SQLStatement实例
//定义数据库文件路径
private var dbFile:File = File.applicationResourceDirectory. resolve("School.db");
//应用程序初始化处理函数
public function initApp():void
{
conn.addEventListener(SQLEvent.OPEN, openHandler); //监听SQLEvent.OPEN状态
//监听SQLErrorEvent.ERROR状态
conn.addEventListener(SQLErrorEvent.ERROR, errorHandle);
conn.open(dbFile); //打开数据库文件
}
//数据库文件打开后的处理函数
private function openHandler(e:SQLEvent):void
{
createStmt.sqlConnection = conn; //定义语句连接的数据库
//sql语句创建表Notes
var sql:String ="CREATE TABLE IF NOT EXISTS Notes ("
+ "noteId INTEGER PRIMARY KEY AUTOINCREMENT,"
+ "title TEXT,"
+ "content TEXT,"
+ "publisher TEXT"
+ ")";
createStmt.text = sql;
//添加对SQLEvent.RESULT状态的监听
createStmt.addEventListener(SQLEvent.RESULT,createTableResult);
//监听SQLErrorEvent.ERROR状态
createStmt.addEventListener(SQLErrorEvent.ERROR, errorHandle);
createStmt.execute(); //执行sql语句
}
//创建完表或已存在表时显示表中的数据
private function createTableResult(e:SQLEvent):void
{
createStmt.sqlConnection = conn; //定义语句连接的数据库
createStmt.text ="select * from Notes";
//添加对SQLEvent.RESULT状态的监听
createStmt.addEventListener(SQLEvent.RESULT,showDataResult);
//监听SQLErrorEvent.ERROR状态
createStmt.addEventListener(SQLErrorEvent.ERROR, errorHandle);
createStmt.execute(); //执行sql语句
}
//显示数据处理函数
private function showDataResult(event:SQLEvent):void
{
dg.dataProvider=createStmt.getResult().data; //绑定数据集
}
//插入数据处理函数
private function insertDataHandle():void
{
var stmt:SQLStatement=new SQLStatement();
stmt.sqlConnection = conn; //定义语句连接的数据库
stmt.text ="insert into Notes(title,content,publisher) values('"
+txtTitle.text+"','"
+txtContent.text+"','"
+txtPublisher.text+"')";
//添加对SQLEvent.RESULT状态的监听
createStmt.addEventListener(SQLEvent.RESULT,showDataResult);
//监听SQLErrorEvent.ERROR状态
stmt.addEventListener(SQLErrorEvent.ERROR, errorHandle);
stmt.execute(); //执行sql语句
}
//对数据库操作出错时的处理函数
private function errorHandle(event:SQLErrorEvent):void
{
Alert.show("Details:", event.error.message);
}
]]>
</mx:Script>
<mx:Panel >
<!--DataGrid组件,用以显示数据-->
<mx:DataGrid id="dg" verticalScrollPolicy="auto">
<mx:columns>
<mx:DataGridColumn headerText="编号" dataField="noteId"/>
<mx:DataGridColumn headerText="标题" dataField="title"/>
<mx:DataGridColumn headerText="内容" dataField="content"/>
<mx:DataGridColumn headerText="发布者" dataField="publisher"/>
</mx:columns>
</mx:DataGrid>
<mx:Canvas height="259" width="401">
<mx:Label text="标题" x="10" y="12"/>
<mx:TextInput x="69" y="10" width="296" id="txtTitle"/> <!--“标题”输入框-->
<mx:Label text="内容" x="10" y="51"/>
<!--“内容”输入框-->
<mx:TextArea x="69" y="50" width="296" height="110" id="txtContent"/>
<mx:Label text="发布者" x="10" y="171"/>
<mx:TextInput width="92" id="txtPublisher" x="69" y="169"/> <!--"发布者"输入框-->
<!--按钮组件,用以添加数据-->
<mx:Button label="确定" id="btnOk" click="insertDataHandle();" x="69" y="218"/>
</mx:Canvas>
</mx:Panel>
</mx:WindowedApplication>
按下Ctrl+F11快捷键编译运行程序。运行效果如图23-3所示。
23.3 升级AIR应用程序
AIR桌面应用程序可导出为air文件。双击此文件就能开始安装应用程序。若系统中已安装旧版的AIR应用程序,双击air文件时会提示更新AIR应用程序。这种方式是非程序性的方式。Flex 3.0中新增Update类,用以升级AIR应用程序。本小节将介绍使用Flex 3.0实现AIR应用程序的升级。
23.3.1 升级前的准备
升级前需要做些准备,包括导出最新版本的AIR应用程序和定义版本信息的文件。
1.导出AIR应用程序
导出的AIR应用程序得到的是一个安装包(.air格式),可双击打开并安装。导出AIR应用程序的步骤如下所示。
单击“File”|“Export…”命令,弹出导出类型对话框,如图23-4所示。
在树型号列表中选择“Adobe AIR”|“Adobe AIR Package”选项,单击“Next”按钮,弹出“设置AIR安装包”对话框,如图23-5所示。

图23-4 导出类型对话框 图23-5 设置AIR安装包对话框
在“Project”文本框中输入导出的工程名。在“Application”文本框中输入工程的启动页(MXML文件)。在“Include files”区域选择要导出的文件。在“Save as”文本框中输入导出的路径。单击“Finish”按钮,完成AIR应用程序的导出。
2.定义版本信息文件
用户可将当前AIR应用程序的版本信息手动存储于TXT文件中,用以判断AIR应用程序是否需要升级。
23.3.2
检查版本信息
用户可使用FileStream类加载版本信息文件,从而获得当前AIR应用程序的版本号。若当前的版本号小于最新的版本号,说明AIR应用程序需要更新。以下代码使用FileStream类加载“version.txt”文件,并判断是否需要更新AIR应用程序。
var theNewestVersion:Number=5; //定义最新的版本号
…
private function checkVersion():void //检查版本号信息
{
/*读取版本号*/
var stream:FileStream = new FileStream();
stream.open(new File("version.txt"), FileMode.READ);
var currVersion:String = stream.readUTFBytes(stream.bytesAvailable);
stream.close();
//若当前版本号小于最新版本号,需要下载最新的air文件
if (currVersion<theNewestVersion)
{
//升级AIR程序
}
}
23.3.3
使用FileStream类下载最新版本
在更新AIR应用程序前,需要下载最新版本的AIR安装包。使用FileStream类可下载任何格式的文件。其语法如下所示。
var FileStream变量:FileStream=new FileStream();
FileStream变量.open(下载文件路径,FileMode.WRITE);
FileStream变量.writeBytes(ByteArray变量,0,ByteArray变量.length);
ByteArray类型用以存储二进制的数据集。其length属性记录了ByteArray变量的长度。以下代码使用FileStream类下载最新版本安装包“p1.air”。
public var fileData:ByteArray = new ByteArray();
…
private function writeAirFile():void //下载air文件处理函数
{
var file1:File = File.desktopDirectory.resolve("p1.air");//下载路径为桌面
var fileStream:FileStream = new FileStream();
fileStream.openAsync(file1, FileMode.WRITE);
fileStream.writeBytes(fileData, 0, fileData.length);//开始写文件
fileStream.close();
}
23.3.4 使用Updater类升级AIR应用程序
在下载完成最新版本的AIR安装包后,可使用Updater类的update方法升级应用程序。其语法如下所示。
Updater变量.update(AIR路径,版本字符串);
版本字符串可自定义,如“1.2”,“1.3”等。以下代码使用Update类将应用程序升级至最新版本。
var ud:Updater=new Updater();
ud.update(new File("newest.air"),"1.3");
23.3.5
升级AIR应用程序实例
本实例中假设最新导出的AIR安装包为1.3版本,并放置于工程“bin”文件夹下。
升级AIR应用程序实例的步骤如下所示。
新建AIR工程。
在“bin”文件夹下的“Preferences”文件夹下创建“version.txt”文件。“version.txt”文件中存储当前应用程序的版本号,如“1.2”(小于最新版本号)。
编写检查版本号函数checkVersion。checkVersion函数的主要功能是读取“version.txt”中的版本号。判断是否需要升级AIR程序。以下代码定义了checkVersion函数。
private function checkVersion():void //检查版本号信息
{
/*读取版本号*/
var stream:FileStream = new FileStream();
stream.open(file, FileMode.READ); //file变量指向“version.txt”
var prevVersion:String = stream.readUTFBytes(stream.bytesAvailable);
stream.close();
//记录的版本小于当前最新版本号时,需要下载最新的air文件
if (prevVersion < currentVersion)
{
urlStream.addEventListener(Event.COMPLETE, loaded); //添加对加载完成的监听
urlStream.load(urlReq); //加载air文件
}
}
编写下载最新版本函数loaded。loaded函数使用FileStream类获得AIR应用程序的二进制数据,并将二进制数据写入到本地的AIR文件中。以下代码定义了loaded函数和writeAirFile函数。
private function loaded(event:Event):void //加载完成后,下载air文件
{
urlStream.readBytes(fileData, 0, urlStream.bytesAvailable); //数据读取到fileData数组中
writeAirFile(); //下载air文件
}
private function writeAirFile():void //写入新的air文件
{
var file1:File = File.desktopDirectory.resolve("p1.air"); //路径为桌面
var fileStream:FileStream = new FileStream();
fileStream.addEventListener(Event.CLOSE, fileClosed); //添加写文件完成的监听
fileStream.openAsync(file1, FileMode.WRITE);
fileStream.writeBytes(fileData, 0, fileData.length); //开始写文件
fileStream.close();
}
编写更新AIR应用程序代码。将最新版本AIR应用程序写入本地路径后,使用update方法更新原程序,同时修改“version.txt”文件。以下代码更新AIR应用程序,并修改“version.txt”文件内的版本号。
private function fileClosed(event:Event):void //下载文件完成处理函数
{
Alert.show("下载文件完成");
/*升级版本*/
var updater:Updater = new Updater();
var airFile:File = File.desktopDirectory.resolve("p1.air");
var version:String = currentVersion;
updater.update(airFile, version); //开始升级版本
saveFile(); //存储当前版本信息
}
private function saveFile():void //存储最新版本号
{
var stream:FileStream = new FileStream();
stream.open(file, FileMode.WRITE); //file变量指向“version.txt”
stream.writeUTFBytes(currentVersion);
stream.close();
}
完成剩余代码。剩余代码包括程序初始化函数、变量定义、类的引用等。
以下代码是完整的应用程序代码。
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
applicationComplete="init()">
<mx:Script>
<![CDATA[
import flash.filesystem.*; //引用flash.filesystem下的类
import mx.controls.Alert; //引用Alert类
public var file:File; //定义File实例
[Bindable]
public var currentVersion:String = "1.3"; //定义最新版本号
public var urlString:String ="p1.air"; //最新版本air的路径
//定义URLRequest实例
public var urlReq:URLRequest = new URLRequest(urlString);
public var urlStream:URLStream = new URLStream(); //定义URLStream实例
public var fileData:ByteArray = new ByteArray(); //定义ByteArray实例
public function init():void //应用程序初始化处理函数
{
//“version.txt”存储版本信息
file = File.applicationResourceDirectory.resolve ("Preferences /version.txt");
if(file.exists) //若文件存在时,检查版本号
{
checkVersion();
}
else //若文件不存在时,创建文件
{
firstRun();
}
}
private function checkVersion():void //检查版本号信息
{
/*读取版本号*/
var stream:FileStream = new FileStream();
stream.open(file, FileMode.READ);
var prevVersion:String = stream.readUTFBytes(stream. bytes Available);
stream.close();
//记录的版本小于当前最新版本号时,需要下载最新的air文件
if (prevVersion < currentVersion)
{
//添加对加载完成的监听
urlStream.addEventListener(Event.COMPLETE, loaded);
urlStream.load(urlReq); //加载air文件
}
}
private function firstRun():void
{
saveFile(); //存储当前版本号
}
private function saveFile():void //存储当前版本处理函数
{
var stream:FileStream = new FileStream();
stream.open(file, FileMode.WRITE);
stream.writeUTFBytes(currentVersion);
stream.close();
}
private function loaded(event:Event):void //加载完成后,下载air文件
{
//数据读取到fileData数组中
urlStream.readBytes(fileData, 0, urlStream.bytesAvailable);
writeAirFile(); //下载air文件
}
private function writeAirFile():void //下载air文件处理函数
{
//下载路径为桌面
var file1:File = File.desktopDirectory.resolve("p1.air");
var fileStream:FileStream = new FileStream();
//添加写文件完成的监听
fileStream.addEventListener(Event.CLOSE, fileClosed);
fileStream.openAsync(file1, FileMode.WRITE);
fileStream.writeBytes(fileData, 0, fileData.length); //开始写文件
fileStream.close();
}
private function fileClosed(event:Event):void //下载文件完成处理函数
{
Alert.show("下载文件完成");
/*升级版本*/
var updater:Updater = new Updater();
var airFile:File = File.desktopDirectory.resolve("p1.air");
var version:String = currentVersion;
updater.update(airFile, version); //开始升级版本
saveFile(); //存储当前版本信息
}
]]>
</mx:Script>
<mx:Label fontSize="35" text="版本{currentVersion}" horizontalCenter="0" verticalCenter="0"/>
</mx:WindowedApplication>
按下Ctrl+F11键,编译运行程序。运行效果如图23-6所示。

图23-7 升级AIR应用程序实例的运行效果
23.4 Flex 3.0中使用Ajax技术
在前面章节里曾介绍过Flex 3.0中如何使用其他Web开发技术,但未涉及Ajax技术。Ajax技术是一种非常流行的Web开发技术,其主要特点是无刷新性。本章将介绍Ajax技术的基础知识及如何在Flex 3.0中使用Ajax技术。
23.4.1
Ajax技术简介
Ajax是“Asynchronous JavaScript and XML”(异步JavaScript和XML)的简称。Ajax技术是一组技术的结合。Ajax利用通信技术(以SOAP和XML为代表)向服务器发送和接收异步请求和响应,然后使用JavaScript、DOM、HTML、CSS技术来处理响应。
Ajax技术通过JavaScript语言调用服务器端的方法,而不需要刷新浏览器,从而减轻了服务器端的负担,也更快捷地响应用户交互。另外,Ajax不需要任何浏览器插件,但浏览器需要允许运行JavaScript。
Ajax技术具体包括如下五种技术:
(47) 使用XHTML+CSS的表示样式。
(48) 使用DOM(Document Object Model)进行动态显示及交互。
(49) 使用XML和XSLT进行数据交换及相关操作。
(50) 使用XMLHttpRequest类进行异步数据查询、检索。
(51) 使用JavaScript整合所有技术。
使用Ajax开发Web应用程序最关键的技术是JavaScript语言和XMLHttpRequest类。本书中不展开详解Ajax技术开发,着重介绍如何在Flex 3.0中调用Ajax技术。
23.4.2
使用<mx:HTML>组件调用Ajax技术
在Flex 3.0中使用<mx:HTML>组件可加载包含Ajax技术的网页,其语法如下所示。
<mx:HTML id="HTML组件id"… location="网页路径"/>
以下代码使用<mx:HTML>组件加载了“www.google.cn”网页。
<mx:HTML id="html" location="www.google.cn"/>
<mx:HTML>组件在加载网页时,加载网页中的全部内容,包括JavaScript(JavaScript是Ajax技术实现的关键)。Flex 3.0中调用JavaScript函数的语法如下所示。
HTML组件id.htmlControl.window.javascript函数(参数列表);
以下代码在单击“OK”按钮时,调用“test.html”网页中的javascript函数init。
<mx:HTML id="html" location="test.html"/>
<mx:Button label="OK" click="html.htmlControl.window.init();"/>
23.4.3
Flex应用程序结合Ajax技术实例
Ajax技术已广泛应用于互联网的开发。许多无刷新的网页或有动态效果网页都使用了Ajax技术。其中,应用Ajax技术最成功的例子是Google的地图搜索。本小节中将调用Google公司免费提供的包含Ajax技术的测试网页来实现地图搜索功能。Flex 3.0结合Ajax技术实例的步骤如下所示。
新建AIR工程。
编写“yahoo.html”文件。
“yahoo.html”文件是HTML网页,包含了自定义的javascript函数来完成地图搜索功能。以下代码是“yahoo.html”文件的源代码。
<!DOCTYPEhtml
PUBLIC"-//W3C//DTDXHTML1.0Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="http://api.maps.yahoo.com/ajaxymap?v=3.4&appid=mapsnap0" type="text/javascript"/>
<script type="text/javascript">
var Imap; //定义变量Imap
function init()//初始化函数
{
Imap = new YMap(document.getElementById('map')); //使用YMap类初始化Imap变量
Imap.addTypeControl(); //添加类型面板
Imap.addPanControl(); //添加方向面板
Imap.addZoomLong(); //添加缩放长条
Imap.addZoomShort(); //添加缩入短条
//绘制地图
Imap.drawZoomAndCenter('601 Townsend St. San Francisco, CA 94103', 5);
}
function lookupAddress(address) //搜索地址函数
{
//根据地址绘制地图
YEvent.Capture(Imap,
EventsList.onEndGeoCode,
function (result)
{
if (!result.success)
{
alert('This address could not be geo-coded.');
return;
}
Imap.drawZoomAndCenter(result.GeoPoint, 2);
});
Imap.geoCodeAddress(address);
}
window.onload =init; //在网页加载时调用init函数
</script>
</head>
<body>
<div id="map" style="width:800px;height:600px"/>
</body>
</html>
(52) javascript代码定义于<head>标签下的<script>标签下。
(53) “<scriptsrc="http://api.maps.yahoo.com/ajaxymap?v=3.4&appid=mapsnap0" type="text/ javascript"/>”表示引用该地址下的javascript类文件。程序中出现的YMap和YEvent类均在此类文件中定义,但对用户不可见。用户可查看Google Maps官方的使用说明。
(54) HTML网页不会自动执行javascript函数。“window.onload=init;”表示在网页加载时调用init函数。
编写Flex应用程序的外观模型。Flex应用程序的外观模型包括<mx:HTML>组件、输入框组件、按钮组件等。以下代码是外观模型的MXML代码。
<mx:VBox paddingTop="0" paddingLeft="0" width="100%" height="100%">
<mx:HBox width="100%">
<mx:Label text="位置:" color="#ffffff" width="5%"/>
<mx:TextInput width="55%" id="address"/>
<mx:Button label="加载中..." enabled="false" id="mapButton" width="10%"/>
<mx:Button label="保存" width="10%"/>
<mx:Button label="复制" width="10%"/>
</mx:HBox>
<mx:HTML id="map" width="800" height="600"/><!--HTML组件,用以加载网页-->
</mx:VBox>
外观模型效果如图23-8所示。

图23-8 Flex结合Ajax实例的外观效果
添加搜索地图的ActionScript 3.0代码。ActionScript 3.0代码中调用“yahoo.html”文件中的lookupAddress函数来完成搜索功能。实例中有两处需要添加搜索地图的ActionScript 3.0代码:输入框组件的enter事件和“开始搜索”按钮的click事件。enter事件在用户输入数据并按下回车键时触发。以下代码是添加处理后的输入框组件和按钮组件。
<mx:TextInput width="55%" id="address" enter="map.htmlControl.window. lookup Address(address.text);"/>
<mx:Button label="加载中..." enabled="false" id="mapButton" wi
