首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 媒体动画 > flex >

【转】Flex反照

2012-11-23 
【转】Flex反射在很多时候反射为程序的动态性提供了一种可能,从而成了在程序开发设计中必不可少的一种技术。

【转】Flex反射

在很多时候反射为程序的动态性提供了一种可能,从而成了在程序开发设计中必不可少的一种技术。了解 Java 的人都知道,Java 具有反射功能,可以根据类名生成类的实例,获取类的相关方法名称、调用方法等。大名鼎鼎的 Spring 框架,其依赖注入的基础也是建立在反射的基础之上。

同样 Flex 中也提供了类似的反射功能,但由于语言的不同,Flex 代码一般情况下是被编译后形成 swf 文件被加载到浏览器中运行。而且 Flex 中有诸如 Module,RSL(Runtime Shared Library) 等 Java 所没有的特殊技术,所以在 Flex 开发中反射的情况比 Java 更加复杂。

本文中将全面的讨论普通情况,以及使用 RSL 和 Module 技术情况下的 Flex 反射问题。

// 尝试一下去掉下面两个变量的定义再次运行看看程序会不会有异常?privatevar pa:PersonImplA; privatevar pb:PersonImplB; privatefunction sayHello():void { var classRefrence:Class = getDefinitionByName( classCombo.selectedItem.data.toString()) as Class; var classInstance:IPerson = new classRefrence() as IPerson; str = classInstance.sayHello(); } ]]> </mx:Script> <mx:HBox> <mx:Text text="请选择 Class"/> <mx:ComboBox id="classCombo" dataProvider="{classArray}" change="str='';"> </mx:ComboBox> <mx:Button label="运行 sayHello()" click="sayHello()"/> <mx:Text text="{str}"/> </mx:HBox> </mx:Application>

?

从图 1 的程序运行结果我们可以看出,当我们选择不同的实现类类名的时候,程序会根据我们的选择反射出相应实现类的实例,进而输出不同的结果。


图 1:反射运行效果图
【转】Flex反照

值得注意的是,程序中定义了两个变量 pa 和 pb,但实际上并没有使用到它们。如果我们按照程序中的注释,将变量 pa 和 pb 的定义去掉然后运行,我们将会看到程序会有如图 2 的反射异常产生。


图 2:反射异常
【转】Flex反照

原来 Flex 将 MainApp.mxml 编译成 MainApp.swf 的时候,默认情况下不会将所有 import 的类都编译到 MainApp.swf 中去,只有真正使用到的类才会被编译进去。所以当我们将变量 pa 和 pb 的定义注释掉以后,com.test.PersonImplA 和 com.test.PersonImplB 都不会被编译到 MainApp.swf 中去。此时 MainApp.swf 被浏览器 load 到客户端运行的时候,由于找不到相应的类定义所以就产生了反射异常。有些读者在遇到这类问题的时候常常会抱怨 Flex,实际上 Flex 这样的做法也是为了减小生成的 swf 文件的大小。另外,如果不是使用 FlexBuilder 自动编译生成的 swf 文件,而是自己通过 Ant 脚本来编译的话,则可以通过向 Flex 的 Ant compc 任务增加 include-sources 参数来指定将哪些类编译到 swc 和 swf 中去。关于 Flex 的 Ant 脚本编译问题不是本文重点,不再赘述。有兴趣的读者可以查阅 Flex 的 Doc。

在使用 Flex 开发应用程序的时候,我们通常会使用 RSL 技术在多个应用程序间共享库,从而实现减少 Flex 应用程序大小的目的。那么在使用 RSL 的情况下,反射又会是什么情况呢?

发现了电能生磁以后,法拉第用了十年的时间才发现了磁也能生电。我们从主应用中成功的反射 RSL 中的类以后,接下来我们是不是也要进行一个反向实验呢?没错,我们下面要从 RSL 中反射主应用中的类。

?

同样,运行我们的主应用程序 MainApp, 我们可以看到从 RSL 中也可以成功反射主应用中的类。


图 4:从 RSL 中反射主应用中的类
【转】Flex反照

刚才我们进行了从主应用反射 RSL 中类,以及从 RSL 反射主应用中类两组实验。关于 RSL 的反射,还有更多的主题。有兴趣的读者可以自己尝试一下在两个 RSL 项目之间互相反射。以及再建立一个主应用 MainApp2, 让 MainApp 和 MainApp2 两个主应用共享同一个 RSLApp, 尝试一下从 MainApp2 中是否可以成功反射由 MainApp 载入的 RSLApp 中的类。本文不再赘述。

到此为止,我们似乎可以得到一个结论。只要被反射的类被编译到 swf 中,并且被浏览器加载到客户端 FlashPlayer 中,我们就可以任意的进行反射。但是事实上到底真的如此么?还可以让我们来一起看一看反射在 Module 中的情况。

?

并且我们新建一个 SampleModule,我们在 SampleModule 中定义了一个 PersonImplE 类型的变量就是为了把 com.module.PersonImplE 编译到 SampleModule.swf 中去。


清单 8:SampleModule.mxml

// 定义这个变量是为了让 com.module.PersonImplE 编译到 SampleModule 中privatevar pe:PersonImplE; ]]> </mx:Script> </mx:Module>

?

现在我们修改 MainApp.mxml,在 MainApp 在初始化的时候载入 SampleModule.swf

代码如清单 9 所示:


清单 9:SampleModule.mxml

到此为止,似乎一切顺利。和我们在 RSL 部分得出的结论没有任何差别。别急,注意清单 9 中的注释,将 assetModule.load(ApplicationDomain.currentDomain); 替换成 assetModule.load(); 再运行一下程序,看看是不是得到了令人厌恶的反射异常?别着急,讨厌的还不仅如此,如果你不是使用 ModuleManager,而是使用例如清单 10 所示的几种方式,看看会有什么不同的测试结果?


清单 10:用不同的方式载入 Module

  private function loadModule():void  {  // 第一种方式 : 用 ModuleManager 来载入 Module     assetModule = ModuleManager.getModule("com/module/SampleModule.swf");     // 将下面这行代码换成 assetModule.load(); 看看反射时候还会成功?     assetModule.load(ApplicationDomain.currentDomain);         // 第二种方式 : 用 ModuleLoader 试试看能否反射成功?//moduleLoader.applicationDomain = ApplicationDomain.currentDomain;//moduleLoader.loadModule("com/module/SampleModule.swf");// 第三种方式 : 设置 applicationDomain 和 load 的顺序颠倒一下看看反射是否还能成功?//moduleLoader.loadModule("com/module/SampleModule.swf");           //moduleLoader.applicationDomain = ApplicationDomain.currentDomain;  } 

?

有兴趣的读者可以深入的研究 Module 的载入域和反射结果的关系,还可以像我们讨论 RSL 反射的部分一样,对不同 Module 之间的反射进行实验。本文不再赘述。

结束语

相对开发过程中讨厌的反射异常,也许坐下来对 Flex 的反射做一次全面的总结整理感觉可能会更好。本文总结了 Flex 在很多种情况下的反射情况,限于篇幅没有给出全部的答案,有兴趣的读者可以对全部场景都加以实验并作出全面整理。

代码示例和安装要求

本文所有示例均在 Windows XP SP3 系统中测试完成。您需要一台能流畅运行 Windows XP 系统的机器,除此之外您还需要一些工具才能试用本教程中的代码。所有这些工具都可以免费下载:

Java SDK 1.5 或更高版本

Tomcat 6.0 或更高版本

Eclipse 3.4 或更高版本

Flex Builder 3.0.2 或更高版本

FireFox2.0 或更高版本

对于 Flex 开发环境的搭建和 Flex 开发的基础知识请参考本系列教程第一篇?

热点排行