第一篇 敲开FLEX的大门

 

第一篇        敲开FLEX的大门

WEB2.0的时代是一个概念已经被过度泛滥的时代.身为程序员的我们何尝不是一个个孤独的剑客泛舟在波涛汹涌的概念海洋里, 被风雨不断地吹打,磨砺,淘汰和新生。身为剑客,我们一直在为命运杀戮. 所谓的武功秘籍到处都是。 狠心花点银子买来一本,在不为人知的山谷中苦练时日,以便重出江湖,成为令狐冲,张无忌,杨过,又或者是另一个东方不败! 他们的腰里都别着不是<<独孤九剑手抄本>>就是<<九阴真经>>,<<葵花宝典>>.本秘籍的第一页绝对没有写“欲练此功,必先自宫”的系统需求,务必请各位读者放心。废话少说,在本书的首篇里,老李将竭力讨论几个问题。一是当前的RIA世界、RIA世界的主流框架,认识FLEXFLEX集成开发环境等。

 

第一章 今天的RIA世界

1.1    什么是RIA,为什么RIA?

RIA全称Rich Internet Application,翻译过来就是富因特网应用。WEB开发有若干体系,CLIENT/SERVER, BROWSE/SERVER. 传统的WEB开发基本上是基于页面的浏览器和数据请求、响应的服务器方式。近年来用户越来越不满足朴素的HTML表现层展示方式,。在用户体验上,传统的HTML标签已经无法满足用户的体验要求. 为解决这个问题,RIA应运而生了. 既然RIA是富互联网应用的意思.“富”的概念包含三个方面.

. 富数据模型

          意思是用户界面可以显示和操作更为复杂的嵌入在客户端的数据模型,它可以操作客户端的计算和非同步的发送接收数据. 思想是减少数据从客户端到服务器的数据传输次数和负载,以便客户端程序可以更多更好的相应用户动作,提高了用户操作界面的连续性.参考图1-1-1.

. 富用户界面元素集合.

          RIA成熟的方案中基本都提供了传统HTML标签所远远不及的友好用户界面元素,配合数据模型的绑定大大地提高了用户的使用体验.线性的BS模型是用户提交页面操作数据集到服务器,然后服务器同步地响应单一的客户端请求,如此机械地循环往复,造成了频繁的数据库请求和页面刷新,这大大地加重了服务器的负载,数据网络传输的负载,从而造成了用户响应的延迟等. 如果采用富客户界面,可以从以前的服务器响应影响整个界面,转移到只有收到请求的应用程序部分才会做出相应的变化。这本质上意味着界面被分解成许多独立的模块,这些模块都会对收到的信息做出相应的反应,有些会和服务器端进行交互,有些是这些模块之间的通信。参考图1-1-2

. 瘦服务器数据处理模式

既然基本的数据处理在客户端进行解析,那么也就是说服务器不再统一处理所有客户端所需求的数据处理工作,这大大提高了服务器的负载,从而可以并发地处理更多的客户端请求,.

综上所述,富客户端的思想使加强用户操作体验而不频繁的装载刷新数据成为可能;另外RIA是基于用户事件出发的,较好的实时反馈和用户验证特性;丰富的组件资源可以利用;可以集成音频视频,增加用户体验等.

 

1.2    怎样RIA

RIA概念的提出起源于企业级系统尤其是J2EE架构的实施.最初的设计思想是主要为了提高用户体验,把一部分操作逻辑从服务器端转移到客户端来运行.就我个人的实际项目开发经验,本人认为Flex开发的核心在于以下几个方面.

. 首先,能否理解Flex核心类库和运行方式直接决定项目最终的质量,不是说你不能实现功能.既然是富客户,也就是说瘦服务端基本处理一些核心的业务逻辑和事务管理从而为富客户提供数据和会话支持.如果没有仔细考虑Flex表现层的设计,不能为之提供一个合理的数据处理和展现方式的话,最终我们应用程序的执行效率以及可维护和扩展性就很成问题.而这一切的基础就是对Flex核心类库以及运行方式的理解.

.能否理解Flex不但能渲染出华丽的页面而且也能和J2EE等企业级开发架构很好的集成,决定你是一般的玩家或者是高级的开发者.我们用Flex展现表现层,仅此而已.它背后的东西还很多,不过这些和Flex倒没有什么必然的关系,WebService,Spring Remoting Object,ORMaping工具等等.如果你只能用Flex的标准组件做些可以简单操作的小动画,那么你还有很长的一段路要走.

. 理解一个设计框架如Cairngorm+Module,但并不是说你的任何一个项目都要用它,形而上学总是让人讨厌.Cairngorm的优点是利用几个经典的设计模式如Singleton, Front Controller,Delegater等在表现层实现了一个局部的MVC,为开发者提供了很好的逻辑隔离,保证了ACTIONSCRIPT逻辑的松偶合.但它的优点也是它的缺点,完成一次用户交互从Event DispatcherService Locator需要很多个层次.有点麻烦和死板.所以最好的建议是具体问题具体分析,并不是每个用户动作都一定要走这个过程.

. 深入理解Flex的调试机制,它的Profiler工具对我们最终的系统调试和性能优化很有帮助的.

 

以上几点只是实际开发过程中对如何才能深入地掌握Flex这种最前沿的RIA架构的一点感触.Flex最初在2003年由Macromedia公司发布,由于其恶劣的执行效率和开发工具而夭折,直到Flex1.5的发布才真正的商业化,笔者也是在这个时候真正的将Flex纳入真实系统的的解决方案中的.在写这本书的时候,Flex2.0已经发布,并且Flex3也即将发布.Flex2是一个真正的里程碑,依赖其强大的功能和开发工具.Flex已经在RIA解决方案中确立了自己的位置.并且价格也降低了很多.

1.3    RIA主流框架浏览

既然这么好一个思想绝对不可能只有一个人或公司来关注,就像我们已经提及的,RIA总是在内嵌的客户端引擎(比如IE)或虚拟机(比如AVM)的基础上,运行在客户端浏览器中(当然也可以在桌面上如AIR方案).比如我们的FLEX.我们可以创建基于MXML或者ACTIONSCRIPT3FLEX应用.此应用可以运行在一个高效率的以SWF字节码为吞吐方式的多媒体虚拟机内,名字叫AVM,在运行时,AVMJIT(JUST-IN-TIME)编译转换器将SWF字节码转换为二进制机器码.(小插曲: FLEX2.0JIT才被集成进来).另外OPEN LASZLOFLEX的近亲,运行方式基本差不多.

 

1.3.1       ADOBE FLEX

FLEX3应用程序运行在跨平台的FLASH PLAYER9,内嵌一个轻量级的高校的多媒体AVM虚拟机.技术框架主要包括:

.           基于标签的MXML编程语言.程序员可以用其中的可视组件集合以标签的方式设计应用的外观和布局.同时非可视标签元素基本上都是与数据存储,处理和传输有关.

.           ACTION SCRIPT3.一个基于ECMA SCRIPT标准的面向对象的编程语言. 程序员可以在AS中以OO的方式设计应用布局外观以及合适的逻辑处理.

.           FDS(FLEX DATA SERVICES), 我们用它把前台客户端程序集成到后台J2EE服务器架构中.

.           CHARTING组件集合, 一个可以丰富各类图表展示控件集合.不过,现在还没有免费哦!

.           FLEX BUILDER IDE, 一个FLEX应用集成开发环境.包括单机版和ECLIPSE插件版.

FLEX3是一个很灵活的体系架构,核心类库可以方便的被扩展.和集成到服务器端的开发框架比如J2EE,PHP,COLDFUSION,RUBY,.NET.另外,FLEX3中的APOLLO为创建基于HTML,PDF,FLEX,以及FLASH PLAYER的桌面应用程序提供可能.ADOBE 目前的开源战略也逐渐地被用户接受,FLEX1.5的时候没有什么是免费的,2.0开始对开发者来说可以选择的免费东西有,MXML,AS3,FLASH PLAYER9,基于命令行的编译器和调试器,CPU FDS服务器集成架构. 目前依然收费的东西有,FLEX BUILDER包括单机版和ECLIPSE插件版,图表组件,100个并发访问的非单CPU服务器FDS.

创建一个FLEX应用程序的基本选择有简单的包括以下几个步骤.

.           利用标签或者FLEX可视组件类创建组件如:

以标签方式创建组件:

<mx:Label id=testLabel text=label test width=100 height=30 keyDown=keyDownHandler(event)/>

以组件类方式创建组件:

var label:Label = new mx.controls.Label();

.           为组件添加事件响应逻辑,可以在单独的<mx:script>标签中创建,也可以在单独的ACTIONSCRIPT 类中创建.

 Public function keyDownHandler(){mx.controls.Alert.show(key down!);}

.           编译和部署应用.无论在命令行中还是在FLEX BUILDER IDE,编译过程是首先将MXML文件翻译成ACTIONSCRIPT文件,然后FLEX编译器将ACTIONSCRIPT文件统一编译成SWF字节码,FLASH PLAYER9 内嵌的AVM解释执行.

.           部署你的应用到服务器(可选).

在企业级开发中我们通常不可避免地应用到FDS来远程地存取服务器端业务数据对象,消息服务.持久化对象到数据库等等.如图1.1

 

1.3.2       WPF

WinFX是下一代的Windows API,而WPF将是WinFX的核心一部分,用于处理UI, Document, Media和用户交互.WPF包括一个引擎和预装在Windows Vista系统中的架构以及一个名字叫

XAML的基于标签的脚本语言组成。XAMLMXML很相象都是标签封装对象的设计。WPF可以开发基于桌面或者WEB的应用。WPFFlex强壮的地方是本身对三维数据展示的支持,相比之下Flex则暂时只能在2D上游荡。

 

1.3.3       AJAX

AjaxAsynchronous JavaScript and XML的缩写,其核心思想主要有,

1. 使用XHTMLCSS标准化显示

2. 使用DOM(Document Object Model)动态显示和交互

3. 使用XMLXSLT进行数据交互和处理

4. 使用XMLHttpRequest进行异步数据获取

5. 使用JavaScript整合所有这一切(这部分被称为Ajax Engine)

Ajax并不是新技术,它所包含的技术可能5年前甚至更早就出现了.传统的web应用程序一般是由客户端浏览器向服务器提交数据,服务器返回新的页面,再次在浏览器中显示,这意味着每次

数据往返都需要刷新浏览器页面。Ajax应用程序改变了这种模式。由Javascript编写的Ajax引擎(Ajax Engine),在Ajax应用程序中担负着一个中间层的任务,当用户界面要向服务器提交数据时,由Ajax引擎负责收集数据并通过HttpRequest (XMLHttpRequest)向服务器发送数据,服务器处理完成后返回XMLAjax引擎将XML处理为便于用户界面显示的XHTMLCSS数据,并更新用户界面相应部分的显示,而非刷新整个页面,从而避免了不必要的数据往返,只有必要的数据在必要的时刻才在浏览器和服务器之间传输。

1.3.4       OPEN LASZLO

OpenLaszloFlex一样,首先编译成swf,运行时被flashplayer解析。她目前完全opensource,编程主要用JavaScriptXML编码原文件扩展名为LZX。它的有些特点和flex挺像的,不仅可以被编译成swf,而且提供了和flex类似的组件库但是数量和质量比起Flex都远远不及。在Flex1.5时它曾因开源吸引了无数人的目光。前景值得关注.

 

 

 

 

 

第二章          认识FLEX

2.1 FLEX 概览

2004年,Macromedia发布了Flex1.02005年,1.5发布。它比上一个版本在功能和稳定性上有很大的提高。在这个版本中首次加入了图表Charting组件,改进了DataGrid组件,首次加入了控件外观Skinning技术。1.5主要面对的是大型公司,因其价格昂贵,所以没有很好地得到普及。20062.0的发布改变了这一现状。License价格也降到中小公司可以接受的水平,并且重构了FlashPlayer8,应用运行效率得到很大的提高。Flex2更新了MXMLActionScript2语言,使开发者能够方便地利用MXML或者ActionScript3开发和扩展现有的标准组件。同时在Flex系统性能优化方面提出了一个折中的方案就是ModuleLoader,也就是所谓的LazyLoad策略。Adobe同时还提供了和Eclipse集成的Flex Builder 插件 IDE。与1.5不同,这个版本还提供FDS应用服务器,对数据Model这一块提供更健壮的封装。另外,Charting组件被单独隔离成一个独立于Flex SDK的产品。最后,FlashPlayer9的改进也是很激动人心的。FlashPlayer9就整体架构而言与历史版本完全不同,内置的AVM虚拟机能够更快的解析应用程序如图2-1-1

并且对ActionScript3的面向对象编程模式提供完全支持。支持正则表达式,标准事件模型,二进制套接字等。任何一种伟大的技术都是逐渐地从脆弱走向成熟。Flex本身也有很多不足,这种方案并不能解决企业开发中的所有问题。但是,我们已经看到它在一步一步的走向成熟。跟着它成长的脚印,让我们先简单地罗列一些它的一些不足,从Flex1.5开始。

.  不支持鼠标双击事件(解决方案是用两次时间间隔500毫秒的单击事件来模拟),2.0解决了这个问题。

.  FlexHttpSessionIE的标准HttpSessionTomcat,WebLogic上部署时没有问题,但是在UnixJRUN上时,Post请求参数不同步(解决方案是在Remote Object实现中手动同步必要的参数,比如如果你把Spring中的Facade Object作为Remote Object2.0有同样的问题。在WebService作为Server端的通信方式时没有类似问题。

.           前期绑定和官方声称的不一致。组件绑定在Flex1.5中分为前期绑定和后期绑定。当Client端装载编译过的mxmlas码流时首先发出的事件是Initialize然后是CreationComplete,当我们分别写两个handler相应这两个事件,如果后期绑定可能用到前期绑定时装载的数据,你就会发现数据有可能会没有装载。在Flex2.0中去除了前期和后期的概念,采用统一的[Bindable]修饰符可以将一个变量绑定到MXML任何组件元素的任何属性上,组件属性可以实时地感知被绑定变量的变化。

.           FlashPlayer 9以前的实现,类层次结构太深,实现很机械死板,存在很多重构的可能,比如一个应用中包括若干容器和组件,每个组件的初始化都要调flash类根结点相同的构造器。配置好Flex自带的Profiler,就可以在Console中看到整个应用在底层的对象创建初始化的所有过程。只要在flex-config.xml中打开开关然后再做些额外的配置就可以了。Flash9 采用了全新的设计,应用字节码统一在AVM虚拟机中以多线程的方式被解析和执行。

. 本身没有好的模式可以直接利用,容易造成mxmlas混在一起,可以选择cairngorm框架,用它的主要好处是可以在表现层实现MVC,很好的隔离了业务逻辑并且在远程数据存取上实现了统一的封装。但是它的优点在某些时候也变成了缺点,就是从EventDispatcher事件分发器到远程业务代理ServiceLocator处理有些复杂。

6 CellRender存在数据类型DataType不匹配的Bug等等。

最后再罗嗦一下,虽然Flex有很多不足,但是它在不断进步不断强大。

 

2.2 FLEX基本编程模式

这一节我们将把目光锁定到Flex的开发模式上。在我们具体的了解怎么利用Flex开发项目之前,首先要明白MXML是什么样的一种语言和ActionScript3是怎么合作开发的,以及Adobe声称的ActionScript3已经完全实现的了面向对象编程是真的吗?以上的问题都是属于Flex编程模式的问题。Flex2编程元素包括MXML语言,ActionScript3脚本语言以及Flex2 类库。

 

2.2.1 MXML/ActionScript

MXML从本质上说一种XML规范的标签语言,主要用来定义描述可视用户接口,如控件类DataGrid,Label,Button,Hslider等,但是也有时用来定义一些非可视的对象比如FDS数据源的封装和绑定,比如WebService连接,数据绑定Binding,还有一些效果类Effects.MXML基本上和HTML的语法很相象,都是利用标签来定义用户接口和基本组件,但是MXML有比HTML更庞大的标签库。HTMLMXML最明显的不同是MXML文件最终由FlashPlayer来编译解析和展示,而HTML是由IE来直接解析和展示。当我们学习任何一种语言是,第一个程序都是hell world。我们也不能免俗。

<?xml version="1.0"?>

<!-- 注释 -->

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

        <mx:Box>

               <mx:TextInput text="Hello World!" />

        </mx:Box>

</mx:Application>

首先Flex MXML文件的注释方式为<!-- 注释 -->。一般一个MXML应用文件的根标签都是<mx:Application>,而xmlns:mx="http://www.adobe.com/2006/mxml" 则定义了Flex类库组件的名字空间,由此说开去,如果我们有自定义的类库或者是第三方类库时,这个地方名字空间的声明是必须的。<mx:Box>是一个容器类对象,<mx:TextInput text="Hello World!" /> 是一个控件类对象。MXML机制规定容器类对象内可以无限内嵌容器类对象或者控件类对象,而控件类对象不能嵌套容器类对象或别的控件类对象。同时无论容器类对象或者控件类对象都有各自所属的属性集合,方法集合,时间集合。TextInputtext就是其中的一个属性。

 ActionScript3是被用来展示Flex2类对象的基础方式。因为所有的MXML标签对象都最终会被编译成AS类对象字节码的。FlashPlayer中的AVM(AS虚拟机)内置了as的所有基础标准类和方法,在运行时,AVM执行展示这些文件字节码。外表上AcitionScriptJavaScript是很相似的。实际上,JavaScript是基于ECMA-262标准的,而ActionScript是基于ECMA-262 Edition4规范的。和JavaScript一样,ActionScript也是一种弱类型的语言。在OO编程模式的实现上,ActionScript还远远不能让人满意,开发者可以把AS写成OO的样子,但是OO核心思想中的封装多态和继承却徒有其表。况且也没有足够的运行时Runtime处理高端需求的弹性,比如Java中的反射机制。作者认为,ActionScript3OO的实现上还有空间可以拓展。

但从脚本语言的观点出发,ActionScript中我们的确可以方便的做很多东西。比如可以写组件事件侦听逻辑,创建新的类对象,处理回调函数,定义包package和组件等。在Flex2应用程序中利用ActionScript脚本的方法和场合有以下几种。

1.在 MXML文件的<mx:Script>标签中插入as代码,这里可以写事件处理函数,自定义事件,错误处理函数,以及任何你想写的as逻辑。

2.在ActionScript文件定义组件类。另外考虑到组件重用,可以将此AS组件编译成swc库文件备用。

3.在ActionScript文件中扩展标准组件。

4.可以把所有的MXML文件<mx:Script>标签中的逻辑放到一个或者若干个AS文件中,用时可以importMXML文件中。上面提到在MXML文件中直接插入AS代码的方法时要用用到<mx:Script>标签,具体语法是

    <mx:Script>

              <![CDATA[

                     import mx.controls.Button;

                     public function myHandler():void{

                            var myButton:Button = new Button();

                            myButton.label = "label";

                     }

              ]]>

       </mx:Script>

在这个标签里,需要注意的地方有几点。

1. 标签要成对出现。

2你不能在标签内定义任何的的类或者接口,因为本身当前的MXML文件就是一个类,ActionScript并没有像Java一样支持内部类定义。

3 [CDATA[标签主要用来告诉编译器标签内的内容不要被解释成MXML语法,而是ActionScript.

4 <mx:Script>标签必须定义在MXML文件根标签的层次否则会出现编译期错误。另外Flex2语法上支持一个MXML文件中定义多个<mx:Script>标签。

下面举一个在MXML文件中使用AS标签的例子。

<?xml version="1.0"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

       <mx:Script>

              <![CDATA[

                     public function doInit():void{

                            var temp:String = "Hello Flex2";

                            textInput.text = temp;

                     }

              ]]>

       </mx:Script>

       <mx:TextInput id="textInput" creationComplete="doInit()" />

</mx:Application>

MXML文件中标签对象都是用id属性来标识的,一个标签对象只能有一个唯一的id.另外需要说明的是只有类的对象才可能有id,这个id就是当前类对象的名字。比如,我们上面定义的TextInput就可以有id属性,但是当我们用mxml语法自定义一个组件类时,组件类根标签是不能设置id属性的,否则会出现编译错误。原因很好理解,因为这个组件MXML文件只是一个类定义,不是一个类对象。只有对象才可能有id,不是吗?有了id我们就可以像MXML文件内全局变量一样任意控制当前类对象的所有属性和事件处理。就像

textInput.text = temp

当你想索引另外的自定义类文件或者标准库文件时有可能会用到import或者include。如你想在as标签内索引Button标准组件可以用这个语法/import mx.controls.Button。另外如果你想用你自定义的一个AS文件中的一个函数,你可以这样写

      <mx:Script>

              <![CDATA[

                     include "myactionscript.as"

              ]]>

       </mx:Script>

2.2.2 Flex2项目源文件的编译过程

首先说明一下,一个完整的Flex应用可以包括MXML文件,ActionScript文件,SWF文件,和SWC文件等。Flex编译器工作的第一个步骤是将主MXML文件以及文件内include的所有子文件转换成一个单独的ActionScript类文件。连接所有被索引(imported)的的库或自定义类文件。最后形成一个可以被部署到服务器上的swf文件。

 

2.2.3 Flex2 类库架构

Flex3类库主要包括可视化组件类,行为类以及系统管理类。整个类库结构非常复杂。不过在我们的开发中主要用到的类包有,

1.mx.utils包,很多有用的工具类在这里定义。

2.mx.collections包,Flex2的数据容器类

3.mx.charts包,各种图形组件包

4.mx.controls包,所有的可视组件类都在这里;

5.flash.events包,flex 事件处理类定义。

6.flash.utils包,flash基础工具类定义,做一些底层控制时经常用到。

 

2.2.4 ActionScript自定义组件

本小结我们将简要地介绍自定义组件的相关基础概念,在哪里创建以及怎么创建的问题。在实际的项目中我们经常需要自己定义一些组件。那么自定义组件的好处主要有两个。首先,自定义组件可以很好的隔离和封装我们通用的表现层逻辑;第二,它可以使我们建立起针对应用的组件库,使我们以后方便的重用这些组件。

    自定义一个组件可以有两种表示形式,一种是利用MXML标准库标签定义组件的形式,另一种在ActionScript中定义组件类。我们都知道任何Flex组件不论是标签形式还是AS形式都最终被FlashPlayer解释成类对象。组件类定义完成后,那么我们到底该怎么以类文件为模板new一个组件对象呢?首先可以说清楚的是,我们基本上有以下4种方式初始化一个组件对象。

1. MXML<mx:Script>标签外,创建MXML类对象。

2. MXML<mx:Script>标签外,创建AS类对象。

3. MXML<mx:Script>标签中,创建AS类对象。

4. MXML<mx:Script>标签中,创建MXML类对象。

举例分析如下

比如我们继承mx.containers.Panell基础类创建一个CustomPanel自定义组件,类文件定义有两种方式分别为CustomPanelAS.asCustomPanelMXML.mxml

CustomPanelAS.as的代码为:

package demo.flexinaction.samples

{

    import mx.containers.Panel;

 

    public class CustomPanelAS extends Panel

    {

        public function CustomPanelAS(){

            super();

        }

    }

}

Package关键字表明了当前类所在的目录位置,这样做主要为在别的mxmlas文件中名字空间的定义提供索引。和Java的类定义很相像,要倒入类定义中需要索引的类文件 mx.containers.Panel。你不能把一个类声明成私有的,private关键字只有被用来定义类私有属性以及私有方法extends关键字说明当前类需要继承的父类。与类同名的方法CustomPanelAS()是当前类的构造器。Flex2不支持构造器的重载。super();说明调用父类的构造器。

CustomPanelMXML.mxml文件代码如下:

<?xml version="1.0" encoding="utf-8"?>

<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" title="CustomPanel rendered by MXML" >

</mx:Panel>

<?xml version="1.0" encoding="utf-8"?>声明了当前mxml文件的schema以及按照utf-8标准编码。xmlns:mx=http://www.adobe.com/2006/mxml声明了Flex2标准类库的名字空间,这样我们才能在标签中利用mx前缀引用标准类库。当然也可以定义为别的名字。或者为空就像xmlns=http://www.adobe.com/2006/mxml,如果这样,那么在引用标准类库的时候就要这样。

<Panel xmlns:mx="http://www.adobe.com/2006/mxml"></Panel>

类文件定义完了,我们看看Flex2中是怎么创建这个对象的。主应用文件是AdobeFlexInAction.mxml,源代码为:

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"

    xmlns:panels="demo.flexinaction.samples.*" initialize="doInit()">

    <mx:Script>

        <![CDATA[

            import demo.flexinaction.samples.CustomPanelAS;

            import demo.flexinaction.samples.CustomPanelMXML;

            private function doInit():void{

                Application运行时(Runtime)动态创建对象

                //1.利用ActionScriptCustomPanelAS创建

                var panelC:CustomPanelAS = new CustomPanelAS();

                //设置对象title属性

                panelC.title = 'CustomPanel rendered by ActionScript';

                //将新创建对象加入父容器

                hbox.addChild(panelC);

                //2.利用MXML组件类文件CustomPanelMXML创建

                var panelD:CustomPanelMXML = new CustomPanelMXML();

                //将新创建对象加入父容器

                hbox.addChild(panelD);

            }

        ]]>

    </mx:Script>

    <mx:VBox id="hbox" width="407" height="414">

        <!--Application初始化时创建对象 -->

        <!--MXML标签中利用组件类文件CustomPanelMXML创建初始化对象 -->

        <panels:CustomPanelMXML id="panelA" />

        <!--MXML标签中利用组件类文件CustomPanelAS创建初始化对象 -->

        <panels:CustomPanelAS id="panelB" title="'CustomPanel rendered by ActionScript"/>

    </mx:VBox>

</mx:Application>

xmlns:panels="demo.flexinaction.samples.*"是我们自定义文件的名字空间,前缀为panels,名字空间的引入主要是为了避免大型应用的类文件名字冲突,利用名字空间,可以很好地避免这个问题。应用初始化时调用doInit()方法。Flex2标准的可视化组件都有initialize事件doInit()为事件处理函数。具体注释请参考代码中的说明。

 

2.3 FLEX BUILDER2 集成开发环境

毫无疑问,Flex BuilderFlex产品库中非常重要的一员。最初版本的Flex BuilderMacromedia开发团队以Dreamwaver平台为蓝图开发的。实践证明这是一次非常失败的尝试。Adobe Flex开发组意识到这个问题,于是果断地扼杀了Flex Builder1以后,便尝试在以Eclipse IDE为基础的平台上,开发了Flex BuilderEclipse 单机版和Flex Builder的插件版以适应不同开发者的需求。原因有若干,一是Eclipse是当前J2EE企业级开发人员非常熟悉并且也很稳定强大的集成开发环境;二是,选定Eclipse作为整体基本框架也是与Adobe未来的开源战略分不开的;最后就是Eclipse极其强大且灵活的扩展性。Flex BuilderEclipse的单机版和插件版两种,其实运作方式大同小异。单机版集成了Eclipse平台的一个子集,运行时比标准的Eclipse平台会消耗更少的内存资源。但是考虑到实际的情况,对已经在利用Eclipse标准平台做系统开发的人员可以考虑用插件版,操作上可以简单的把Flex Builder作为Eclipse的一个标准插件就可以了,十分方便。

我想大家在安装Flex Builder以后,根据创建项目向导就可以成功地创建一个项目。在这里我不想在重复这些具体的操作过程。不过,我认为很有必要说明一下在创建项目时的一些关键概念的理解。

1 Eclipse的其他类型项目一样,只能先创建一个项目,然后才能创建代码源文件mxml或者as

2 创建项目向导中关于存取数据的种类有三种,Basic类型是指从项目本地的XML文件或者是Web服务中存取数据。也就是说这种类型的项目部署时不需要FDS服务器Runtime提供存取数据服务。如果选择FDS类型那么你的这个Flex项目物理位置应该在J2EE WEB应用的WebContent文件夹下。

3 向导中对于主应用文件的命名要慎重,不要与你系统中别的组件mxml文件名重名。输出文件路径系统默认路径是项目目录下Bin子文件夹,也可以自定义。

4 Flex Builder2在创建任何种类型的项目时都会默认地把若干标准swc库导入到项目BuildPath下面,也就是说如果你的项目中要索引到别的第三方库文件的话则必须手动地加入这些类库索引。或者可以手动编辑项目.actionScriptProperties文件将你的类库加入。

5 Flex编译器默认的编译参数为-locale en_US,如果你的项目中有对多语言的支持的话,那么你要把所有的参数都配上去,否则ResourceBundle类可能找不到所需要的多语言properties文件。

Flex Builder的视图有开发视图和调试视图两种。对于开发视图开发者可以方便的在源代码编辑区手动写代码或者在设计模式选项卡中所见既所得的拖动Flex组件,代码会自动更新到代码模式选项卡中,并且这两种开发模式是保持代码同步的。当项目中已设置好断点,调试时Flex Builder会自动切换到调试试图,并停止运行到断点处,开发者可以在单步跟踪的过程中,watch 或者 display所感兴趣的变量。Flex Builder编译项目源文件时,首先会扫描所有源文件,遇到被修改的文件时才会重新编译这个文件,然后连接所有主文件mxml中索引到的所有资源。一般会消耗不少的内存资源,如果你不想每次改完源文件后都让系统重新build一遍项目,那么可以勾掉Flex Builder顶端project菜单中的build automatically选项。在你需要的时候可以手动地build项目。

 

2.4一个恶俗而古老的例子,HELLO WORLD

各位读者,书写到这里,我一直在犹豫不定,到底该不该把本节放进来。对有些读者,本节可能再垃圾不过,可是考虑到那部分初步涉及FLEX的读者可能会感到有些突兀,所以我还是愚蠢的将本章放在了这里。本章是为他们所写。自觉已经熟悉本部分的读者可以完全跳过本章。俗话说,没有这金刚钻,怎敢揽这瓷器活!FLEX开发,我们首先就要非常熟悉FLEX开发调试部署等一系列工具。本章将通过创建最简单的HELLO WORLD程序,向初步关注FLEX的读者展示FLEX开发调试部署等一套工作流程。另外也会简单地分析AS的面向对象特性,结合本恶俗实例分析FLEX应用初始化过程等基本主题。

在我们实际的项目开发中,第一个问题是怎么创建一个项目开发环境。因为我们的项目不止是表现层的开发,还有服务端业务逻辑,数据库操作等,问题是怎么整合它们。比如面向JAVA的开发者正在用FLEX+SPRING+HIBERNATE+SYBASE做一个项目,那么开发环境怎么搭建呢?可选择方案大体可分为两种。一是,FLEX BUILDER单机版创建一个FLEX项目单独做表现层,同时利用ECLIPSE搭建一个J2EE项目做服务端。关键点只是将FLEX项目的源创建在服务端项目的WEBCONTENT(ECLIPSE),或者是WEBROOT(在MYECLIPSE)中。令一种方式是利用FLEX BUILDERECLIPSE插件版直接在J2EE项目的WEB上下文中创建表现层FLEX项目。两种方式其实大同小异。相同点是FLEX项目都要创建在服务端的WEB上下文中。不同的是FLEX项目一个是用单机版,一个使用插件版。可是从效率上讲,第二种方式更加好一些,因为你在开发时没有必要同时打开两个ECLIPSEFLEX BUILDER3也是基于ECLIPSE的),这样可以在开发时节省100M的内存。调试也更方便一些。

 

2.4.1  FLEX几个工具

一.Mxmlc: FLEX的命令行MXMLACTION SCRIPT编译器,此工具的资源包在FLEX SDKmxmlc.jar包中。包中定义了一系列编译链接以及多语言资源路由相关的规范。

二.Compc:通常我们用此工具打包自定义组件为swc库。每个SWC都基本包含一个SWF字节码文件,一个CATALOG.XML目录索引文件,和一些附加的资源文件,如图片,音频,视频等。

三.Fdb:在内置的FLASH PLAYER9 调试版中,我们可以在命令行启动应用的调试线程。不过,说句实在话,我们有FLEX BUILDER集成调试工具,谁还用它呢。不过这些工具都是基础的东西,在利用ANT自动化BUILD我们各式各样的应用时,FLEX BUILDER就不行了,尤其在UNIX平台上。

四.Asdoc: JAVAJAVADOC工具,AS也相应的有ASDOC,大同小异。

另外,上面的工具都是用JAVA写的,所以在编译器需要JRE的支持。这也是JRE被集成到FLEX SDK中的原因。

 

2.4.2 HELLO WORLD

源代码为:

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >

    <mx:Label text="HELLO WORLD!" />

</mx:Application>

 

这里将用基于命令行的方式编译MXML文件。Mxmlc有很多有用的编译选项。不必全部记忆,用到时可以查阅相关文档,或者利用这个命令来查看当前编译器所支持的编译选项列表。

如我们在命令行键入: mxmlc –help list advanced

 

MXML文件都是先被转换成AS文件让后才被编译成SWF字节码,如果你想看看生成的相应AS文件,那么可以用这个命令。

mxmlc -keep-generated-actionscript Demo1.mxml

这个命令会生成一个generated文件夹,里面包含所有生成的中间AS文件。另外,我们也可以根据编译的需要将我们期望的编译选项配置在flex-config.xml文件中,或者自定义的配置文件中。不过这个自定义配置文件的路径全名应该在flex-config.xml中预先指定。可是在实际项目中就不止只有一个HELLO WORLD那么简单。结合服务端的JAVA业务逻辑及配置文件很可能是成千上万的文件需要链接编译。这个时候就需要用ANT BUILD脚本来做这些复杂的工作。我们的HELLO WORLD应用在ANT中就可能是这个样子的。

<project name=”DEMO1” default=”compile”>

<property name=”flex.mxmlc” location=”C:/Program Files/Adobe/C:/flex3/sdks/3.0.0/bin/ mxmlc.exe” />

<property name=”dest.dir” value=”bin-debug” />

<target name=”init”>

<delete dir=”${dest.dir}” />

<mkdir dir=”${dest.dir}” />

<attrib file=”${dest.dir}” readonly=”false”/>

</target>

<target name=”compile” depends=”init”>

<exec executable=”${flex.mxmlc}” failοnerrοr=”true”>

<arg line=”-output ‘${dest.dir}/Demo1.swf’”/>

<arg line=”Demo1.mxml”/>

</exec>

</target>

</project>

初始化任务主要是删除和创建bin-debug输出目录,编译任务调用FLEX编译器编译我们的Demo1.mxmlDemo1.swf字节码文件。

 

2.4.3 MXML文档结构

FLEX的任何MXML文档都是基于容器和组件的,以标签的方式来组织。任何应用的根节点都是Application。容器类实例可以嵌套别的容器类和组件类实例,组件类实例不能嵌套容器实例。容器负责页面的布局,组件负责页面元素的显示。参考一个例子DemoGrid.mxml源代码:

<?xml version="1.0" encoding="utf-8"?>

<!--实例2-4-3-1-->

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" backgroundAlpha="0" creationComplete="srv.send()">

    <mx:Script>

        import mx.collections.ArrayCollection;

        [Bindable]

        public var employees:ArrayCollection;      

    </mx:Script>

    <mx:HTTPService id="srv" url="demo2.1.1/employees.xml" useProxy="false"

        result="employees = srv.lastResult.list.employee"/>

    <mx:HBox width="100%" height="100%">

        <mx:DataGrid id="dg" width="100%" height="100%" dataProvider="{employees}">

            <mx:columns>

                <mx:Array>

                    <mx:DataGridColumn dataField="name" headerText="Name"/>

                    <mx:DataGridColumn dataField="phone" headerText="Phone"/>

                    <mx:DataGridColumn dataField="email" headerText="Email"/>

                </mx:Array>

            </mx:columns>

        </mx:DataGrid>

        <mx:Form width="100%" height="100%">

            <mx:FormItem label="Name">

                <mx:Label text="{dg.selectedItem.name}"/>

            </mx:FormItem>

            <mx:FormItem label="Email">

                <mx:Label text="{dg.selectedItem.email}"/>

            </mx:FormItem>

            <mx:FormItem label="Phone">

                <mx:Label text="{dg.selectedItem.phone}"/>

            </mx:FormItem>

        </mx:Form>

    </mx:HBox>

</mx:Application>

Employee.xml为外部XML数据源:

<?xml version="1.0" encoding="utf-8"?>

<list>

    <employee>

        <name>Louis Freligh</name>

        <phone>555-219-2100</phone>

        <email>lfreligh@fictitious.com</email>

        <active>true</active>

    </employee>

    <employee>

        <name>Ronnie Hodgman</name>

        <phone>555-219-2030</phone>

        <email>rhodgman@fictitious.com</email>

        <active>false</active>

    </employee>

    <employee>

        <name>Joanne Wall</name>

        <phone>555-219-2012</phone>

        <email>jwall@fictitious.com</email>

        <active>true</active>

    </employee>

</list>

运行结果为:

这是一个通过HTTPSERVICE请求远程读取数据源然后在DATAGRID中显示的一个例子。那么在这个例子中,关于文档结构的话题,有几个方面要注意。

源代码第一句定义了文档的SCHEMA和以UTF-8方式编码,而通过第二句

<mx:Application xmlns:mx = "http://www.adobe.com/2006/mxml" backgroundAlpha="0" creationComplete="srv.send()">

我们可以知道以下内容。

1. xmlns:mx定义了一个FLEX标准类库标签的索引,和JSP标签库TLD类似,这个名字MX可以随便定义当然也可以为空,它指定了标准类库在当前应用的名字空间。

2. 每个FLEX标签都对应FLEX标准类库中相应的组件类,比如Application标签则对应mx.core.Application类。

3. 每个组件类,包括可视化或者非可视化类,都提供了若干公共属性接口,公共状态接口,公共事件响应接口等,如Application中的backgroundAlphacreationComplete等。

4. Application没有id属性,因为原理上FlexServlet监听客户端的请求,并实例化相应的mxml类实例。MXML文件是类模板,而不是类实例。那为什么Application标签内嵌入的组件标签可以定义id属性呢?读者如果熟悉OO编程思想,这实际上是一种对象间的合成关系,Application类实例负责所有孩子的生命周期,而且是整体和部分的关系.

关注这段代码,

<mx:Script>

        import mx.collections.ArrayCollection;

        [Bindable]

        public var employees:ArrayCollection;      

    </mx:Script>

FLEX应用中,我们通常要在MXML标签中嵌入mx:Script标签以便写一些必要的对AS操作逻辑,比如对数据的处理,你可以在标签内通过IMPORT关键字导入类或者包、定义变量,设置变量绑定,定义事件响应函数,等等。但是有一点,我们不能在SCRIPT标签内定义一个新类。因为,MXML没有像java一样有嵌套内部类的概念,否则会报编译错误。

FLEX组件对象总体上可分为可视化和非可视化两种,而可视化组件又有容器和组件两类,非可视化有数据容器类,数据存取,状态保持和操作类等。在本例中的非可视化组件HTTPSERVICE远程读取一个静态XML文件,这个过程是异步地,result属性定义了一个异步回调动作,目的是初始化公共绑定对象employees.

<mx:HTTPService id="srv" url="demo2.1.1/employees.xml" seProxy="false"

        result="employees = srv.lastResult.list.employee"/>

对于可视化对象HBOX

<mx:HBox width="100%" height="100%">

        <mx:DataGrid id="dg" width="100%" height="100%" dataProvider="{employees}">

            <mx:columns>

                <mx:Array>

                    <mx:DataGridColumn dataField="name" headerText="Name"/>

                    <mx:DataGridColumn dataField="phone" headerText="Phone"/>

                    <mx:DataGridColumn dataField="email" headerText="Email"/>

                </mx:Array>

            </mx:columns>

        </mx:DataGrid>

        <mx:Form width="100%" height="100%">

            <mx:FormItem label="Name">

                <mx:Label text="{dg.selectedItem.name}"/>

            </mx:FormItem>

            <mx:FormItem label="Email">

                <mx:Label text="{dg.selectedItem.email}"/>

            </mx:FormItem>

            <mx:FormItem label="Phone">

                <mx:Label text="{dg.selectedItem.phone}"/>

            </mx:FormItem>

        </mx:Form>

    </mx:HBox>

我们可以看到HBOX是一个容器,里面嵌套了一个DATAGRID组件和另一个FORM容器。对于初步学习FLEX的读者可能不能完全理解代码中的语法,没有关系。我们将在后续的章节中详细探讨每一个技术细节。在这里只要能够形象地理解MXML文档结构就足够了。

 

2.5         利用FLEX BUILDER创建调试项目

FLEX BUILDER中我们可以方便地做很多工作,分别为

其中开发者只能在某种项目的范围内创建文件。也就是说我们创建的Application,Component, 或者是Module等等文件一定要在某个项目种类里。

MXML Application: 可以在项目中单独运行。

MXML Component: 不能独立运行,不能脱离应用单独编译,可以通过定义名字空间被另一个Application或者Component来索引。

MXML Module: FLEX3为解决性能问题所出的一个折中方案,可以独立编译,但是不能独立运行。在MXML文件中通常要通过ModuleLoader来加载,在AS类文件中通常要通过ModuleManager来加载。

ActionScript File: 定义存放函数和变量的AS文件。

ActionScript Class: 定义AS 类文件。

ActionScript Interface: 定义一个AS接口,此接口可以被别的类实现。接口中所有的函数都是虚函数。对于变量则只能是static final的。

CSS File: 定义样式表文件,可以被编译成swc或者swf文件。

 

现在我们将创建一个菜单项目。目的是了解项目创建调试过程,算做对已经讲过的知识的一个总结。

第一步:FILEàNEWàFLEX PROJECT

第二步:定义项目名称,种类和资源包位置。

第三步:指定编译文件输出地址为bin

第四步:指定项目类路径就是classpath,附加swc开发包以及主应用文件名字。

第五步:在FLEX BUILDER的资源编辑器中编辑源文件FlexDemo2.mxml

<?xml version="1.0"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initCollections();" >

    <mx:Script>

        <![CDATA[

            import mx.events.MenuEvent;

            import mx.controls.Alert;

            import mx.collections.*;

            [Bindable]

            public var menuBarCollection:XMLListCollection;

           

            private var menubarXML:XMLList =

                       <><menuitem label="Menu1" data="top">

                        <menuitem label="MenuItem 1-A" data="1A"/>

                        <menuitem label="MenuItem 1-B" data="1B"/>

                    </menuitem>

                    <menuitem label="Menu2" data="top">

                        <menuitem label="MenuItem 2-A" type="check"  data="2A"/>

                        <menuitem type="separator"/>

                        <menuitem label="MenuItem 2-B" >

                            <menuitem label="SubMenuItem 3-A" type="radio"

                                groupName="one" data="3A"/>

                            <menuitem label="SubMenuItem 3-B" type="radio"

                                groupName="one" data="3B"/>

                        </menuitem>

                    </menuitem></>;

            private function initCollections():void {

                menuBarCollection = new XMLListCollection(menubarXML);

            }

            private function menuHandler(event:MenuEvent):void  {

                if (event.item.@data != "top") {

                    Alert.show("Label: " + event.item.@label + "/n" +

                        "Data: " + event.item.@data, "Clicked menu item");

                }       

            }

         ]]>

    </mx:Script>

    <mx:Panel height="75%" width="75%" paddingTop="10" paddingLeft="10">

        <mx:MenuBar labelField="@label" itemClick="menuHandler(event);"

            dataProvider="{menuBarCollection}" />

    </mx:Panel>

</mx:Application>

 

第六步:编译并运行应用。

当点击某一个叶子菜单项时会弹出一个Alert

第七步:现在我们在源代码31行定一个断点。看起来是

第八步:点击顶部菜单栏RunàDebugàDebug FlexDemo2,然后FLEX BUILDER会自动切换到DEBUG模式并且会当前主线程运行到31行断点处。

同时我们可以在右上角的变量标签栏里实时跟踪当前变量的值,通过表达式标签栏我们可以方便地跟踪某

一表达式的值。

 

2.6         APOLLO

APOLLO将我们带入桌面2.0时代! 在以往的系统开发中桌面系统和WEB系统是截然不同的两种开发模式.APOLLO给我们提供了一座桥,连接桌面应用和WEB应用的一座桥,它现在越来越成熟.APOLLO集成了FLASH PLAYER9,FLEX, JAVASCRIPT,HTML,PDF,同时也提供了访问桌面资源如文件系统,端口的能力.这意味着开发者不仅可以在开发WEB应用的同时访问桌面资源,而且也可以开发类似于WEB的桌面应用.从功能上APOLLO模糊了桌面应用和WEB应用的严格界限.

 

2.7         FLEX学习曲线

很多朋友都在关心完全精通FLEX到底需要多长时间,这个问题我也不知道答案,因人而异. 但是要说熟悉FLEX需要的时间我可以有一个基本的判断三个礼拜.有很多的JAVA程序员都在做WEB应用开发,都熟悉J2EE一套的东西,甚至还包括SWING.. 为什么说三个礼拜呢? 首先,ACTION SCRIPT3 也是一种OO的语言, 语法及编程方式十分相似. 第二, 开发工具FLEX BUILDER是基于ECLIPSE插件模式。开发的.熟悉JAVA的开发者相信大都对ECLIPSE不陌生.第三,FLEX的核心类已经被很好的封装和梳理.经过简单的配置,一个J2EE的程序员就可以搭建起一个很好的FLEX+J2EE的开发框架. 至于精通FLEX,是需要时间和实践的.本书的目的就是尽量缩短读者的学习时间,在近可能短的时间和篇幅里道出真实项目开发中所能积累的经验.

 

2.8  FLEX 的效率问题.

您可能一直在关心着这个问题,毫无疑问如果开发者没有注意到一些细节,你的FLEX应用的效率会很糟糕.同时两个程序员都知道FLEX,一个精通,一个熟悉.他们两个都可以完成这个开发任务,但最终他们系统的效率就是不一样,一个较好,一个则很勉强.这也是初级玩家和有经验的开发者最大的区别. 这不是能不能实现的问题,而是好不好的问题. 其实,用好FLEX还是有很多细节要注意的. 比如页面容器不要嵌套太深。采用LAZYLOAD方式,尽可能重用自定义组件,充分利用PROFILER工具优化系统, 如果可能尽量采用MODULELOADER加载方式等等.在后续章节中, 将有单独的一章,通过示例来完整地分析目前业内最有效的若干性能优化技巧.相信把这些用到实际项目中,效果会立竿见影的.

 

2.9总结

:本章洋洋洒洒地从宏观上介绍了RIA相关的一个值得关注的点. WEB2.0的时代我们RIA思想,它解决了现时代WEB开发的一个用户体验问题. 行业中有很多成熟的框架, 但不得不说FLEX是其中最耀眼的一个,简单快速的开发方式, 完美的可视化组件,及其方便的系统集成等等. 虽然FLEX还是有不少的问题,但是我们可以看到它在进步,在不断的发展和强壮. 从下一章开始我们将进入本书的核心部分, 但是还是建议读者现读完第一章,尤其是对RIA概念不是很清晰的读者. 第二章我将以简练的方式剖析FLEX整体的一些技术细节. 好戏即将开始, 请进入下一章.

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值