|
其實非常簡單, 只需要在application類中定義一個public類型的變量就行了:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
public var foo:String = "bar";
]]>
</mx:Script>
</mx:Application>
在其它的地方就可以使用
Application.application.foo
來訪問了. 如果需要, 也可以添加 Bindable 屬性. 但是要注意到一個問題就是, 在使用的時候編譯器不會進行類型的檢查, 因此最好添加類型強制轉換.
當然, 全局變量實現的另一種方法是使用單例模式.
有許多方法可以把一個應用拆分成基于個獨立下載的部分。甚至于將每個類都分成單獨的文件,由ClassLoader在需要的時候加載。但是如果這樣效率是比較低下的,因為類的引用有著明顯的“引用地域”;如果你引用了一個類,往往會馬上牽涉到需要引用一大堆其他的類,如果把這些類全都打包在一起,效率會高得多。
由編譯器自動選擇一個非常好的打包方法是比較困難的。很可能需要在應用開發時進行一些設定,并不時地監控類的引用。能夠統計出最優的分拆方法:應用應該分成幾個SWF,哪些類應該放在哪個SWF中。但是這種方法聽起來更象是一種研究范疇,實際操作起來非常困難。
讓我們來看一些更具有操作性的方法。
很多應用分解后,包含兩種類型的功能:“啟動后立即填充”和“啟動后稍后填充”。
有許許多多的應用是這種模式的。比如:游戲;你有一個游戲引擎和一些游戲場景。或者Portals和Porlets; 一些基礎的共享功能和數據驅動的小應用。或者是一個大型的有著1500個頁面的保險應用,運行特定功能是只會訪問一小部分的頁面。或者是充斥大量內容的應用,它可以獨立的更新部分內容而不是強制用戶每次瀏覽時都必須下載全部內容。
我稱這些相對獨立的可以延遲加載的功能為“模塊”(Modules),稱加載模塊的應用為“Shell”。
在這里,我們先不看如何做,先來看一些
shell需要能夠與模塊交互,同樣模塊也需要和Shell交互。如果shell引用了modules的一個類,那么它會把它鏈接進來。同樣,如果模塊類引用了shell類,它也會把它鏈接進來。應用能正常運行只有兩個方法:或者引用是相同而且共享的(這樣就不需要下載兩次),或者兩者是不同的,而且沒有任何關系(盡管兩個類名字相同,但是它們被認為是無關的,而且不能交互)。
最好的解決辦法是讓模塊和shell通過接口交互。這樣,shell不需要引用模塊,而是引用模塊會實現的一些接口。同樣,模塊不實現shell的類,而是允許調用的API接口。
這樣在shell變化的時候減少了重新編譯模塊的次數。具體實現的變化頻率往往會比接口本身的變化高得多,而只要接口穩定,就不需要重新編譯所有的東西。
注意:需要使用extern(或者extern-library-path)選項來創建模塊,這樣可以自動剔除shell的類,因為模塊是被加載到shell的子應用域中的,將shell的類剔除是安全的。這樣模塊可以真正直接引用shell中的類。
?
這個例子包括了應用中使用RSL的完整流程。使用命令行進行編譯,但是你可以使用FlexBuilder用相同的過程來創建使用RSL。
記住SWC文件是一個包含SWF文件的二進制文件,而SWF文件包含運行時的定義和附屬元數據。你可以用壓縮工具比如WinZip來打開SWC文件。 在使用RSL之前,首先需要了解如何靜態鏈接一個SWC文件。
在這個例子中,應用有一個app.mxml文件,使用ProductConfigurator.as和ProductView.as。文件目錄如下:
project/src/app.mxml project/libsrc/ProductConfigurator.as project/libsrc/ProductView.as project/lib/ project/bin/
編譯這個應用時,可以使用source-path選項將/libsrc目錄下的類鏈接進來,方法如下:
cd project/src mxmlc -o=../bin/app.swf -source-path+=../libsrc app.mxml
這個命令添加ProductConfigurator和ProductView類到SWF文件中。
如果要創建庫,可以用compc來創建SWC文件,用下面的命令:
cd project compc -source-path+=libsrc -debug=false -o=lib/mylib.swc ProductConfigurator ProductView
注意要將debug選項設置為false. 生成結果是project/lib/mylib.swc文件,包含ProductConfigurator和ProductView兩個類。
現在可以使用新創建的庫來重新編譯應用,用library-path選項來指定庫,方法如下:
cd project/src mxmlc -o=../bin/app.swf -library-path+=../lib/mylib.swc app.mxml
創建庫以后,你可以用RSL來重新編譯生成應用。完整的步驟如下:
?? 1. 指示編譯器不要將庫鏈接到應用中。 ?? 2. 準備RSL,以便于在運行時使用。 ?? 3. 指示編譯器生成附加元數據用于加載RSL。
第一步是指定編譯生成應用時庫中的哪些類需要排除在外。主要是使用external-library-path選項,如下面的例子所示:
cd project/src mxmlc -o=../bin/app.swf -external-library-path+=../lib/mylib.swc app.mxml
如果你嘗試運行app.swf,Flash Player會拋出一個運行時異常。因為ProductConfigurator和ProductView類還未定義。external-library-path配置選項告訴編譯器編譯這些庫,但是忽略了定義。你也可以使用externs選項,但是一般來說,使用external-library-path更方便。
下一步是準備RSL以便于能在運行時找到它。首先從SWC文件中將library.swf解壓出來。
下面是如何解壓的例子:
cd project/lib unzip mylib.swc library.swf mv library.swf ../bin/myrsl.swf
此例子中將library.swf更名為myrsl.swf,并把它移動到應用SWF文件所在的目錄。
最后一步是使用RSL重新編譯應用。主要是使用runtime-shared-libraries選項,方法如下:
cd project/src mxmlc -o=../bin/app.swf -external-library-path+=../lib/mylib.swc -runtime-shared-libraries=myrsl.swf app.mxml
現在新的SWF文件會在運行應用前動態加載RSL了。
在編譯應用時要使用RSL, 需要使用下列編譯選項:
??? * runtime-shared-libraries 提供運行運行時共享庫的位置. ??? * external-library-path|externs|load-externs 提供編譯時庫的位置. 編譯器需要這個信息動態鏈接.
使用runtime-shared-libraries選項來指定SWF文件的位置, 這樣應用能夠在運行時加載RSL. 需要指定SWF與部署位置的相對路徑. 比如: 如果把library.swf文件放在web_root/libraries目錄下, 而應用在web_root目錄下, 那么文件的指定方法是: libraries/library.swf 可以用這個選項指定多個庫. 如果指定了多個庫, 需要用逗號分隔.
使用external-library-path選項來指定library在編譯時的SWC文件或者目錄的位置. 編譯器會在編譯時根據這個選項進行鏈接的檢查. 你還可以使用externs或者load-externs選項來指定其他單獨的classes或者xml文件來定義庫的內容.
下面是一個編譯MyApp應用的命令行示例, 其中使用了2個庫:
mxmlc -runtime-shared-libraries= ../libraries/CustomCellRenderer/library.swf, ../libraries/CustomDataGrid/library.swf -external-library-path=../libraries/CustomCellRenderer, ../libraries/CustomDataGrid MyApp.mxml
庫的順序非常重要, 因為基礎類必須先加載.
你先可以使用配置文件, 示例如下:
<compiler> ??? <external-library-path> ??????? <path-element>../libraries/CustomCellRenderer</path-element> ??????? <path-element>../libraries/CustomDataGrid</path-element> ??????? <path-element>../libs/playerglobal.swc</path-element> ??? </external-library-path> </compiler> <runtime-shared-libraries> ??? <url>../libraries/CustomCellRenderer/library.swf</url> ??? <url>../libraries/CustomDataGrid/library.swf</url> </runtime-shared-libraries>
runtime-shared-libraries選項值是library.swf文件是相對部署目錄的路徑. external-library-path選項是編譯時SWC文件的路徑. 因此, 必須先知道庫的部署路徑.
?
示例中, 編譯時文件結構如下:
c:/appfiles/MyApp.mxml c:/libraries/CustomCellRenderer/CustomCellRenderer.swc c:/libraries/CustomDataGrid/CustomDataGrid.swc
library.swf在編譯進不是必需的. Flex編譯器不驗證SWF文件的存在與否, 但會把路徑信息編譯進行最后的應用代碼中.
文件的部署結構如下:
web_root/MyApp.swf web_root/libraries/CustomCellRenderer/library.swf web_root/libraries/CustomDataGrid/library.swf
?
創建庫
可以使用Flex Builder或者Compc命令行來創建庫. 庫可以是一個SWC文件, 或者是包含了library.swf和catalog.xml文件的目錄. 一個庫通常包含自定義組件和類. 然后就可以在RSL中使用這些庫了.
在Flex Bulder中, 通過使用Flex Library Build Path對話框來添加資源到庫中.
在命令行中, 使用include-classes和include-namespaces選項來添加文件到庫中.
下面的命令行示例說明了如何創建一個名字叫CustomCellRenderer的庫:
compc -source-path ../mycomponents/components/local -include-classes CustomCellRendererComponent -directory=true -debug=false -output ../libraries/CustomCellRenderer
所有包含的組件必須是靜態鏈接的文件. 使用compc編譯器創建庫時, 不能使用include-file選項, 因為這個選項不是將library.swf文件靜態鏈接到庫中的.
可以使用directory選項指定輸出到一個目錄而不是到一個SWC文件中:
<?xml version="1.0"> <flex-config> ??? <compiler> ??????? <source-path> ??????????? <path-element>mycomponents/components/local</path-element> ??????? </source-path> ??? </compiler> ??? <output>libraries/CustomCellRenderer</output> ??? <directory>true</directory> ??? <debug>false</false> ??? <include-classes> ??????? <class>CustomCellRendererComponent</class> ??? </include-classes> </flex-config>
輸出會是一個目錄,目錄里包含兩個文件 ??? * catalog.xml ??? * library.swf
創建library.swf文件后, 你可以編譯應用并且指定文件的位置.
UI的問題如何解決呢: AWT, Swing, SWT, 或者是一些其他的比如: Tkinter, WxPython之類的東西? Bruce認為這些對于創建一個真正跨平臺的應用是不夠的. 他認為最好的解決方案就是Flex!
Flex and Flash provide a complete, unlimited, flexible tool to build user experiences. From the standpoint of a programmer’s time investment, you can learn a single language for building UIs without worrying about running into problems or limitations later—issues like:
- Installation problems
- Constraints on what you can create
- Sudden steep climbs in the learning curve
原文鏈接:
http://www.artima.com/weblogs/viewpost.jsp?thread=193593
Computing Thoughts
Hybridizing Java
by Bruce Eckel
January 30, 2007
RSL也需要謹慎使用
RSL也不是對于所有的應用都是有益的. 需要對應用RSL前后的下載時間和啟動時間都測試過, 才能得到正確的結論.
RSL不能跨域共享. 如果客戶在一個域中使用了RSL, 然后運行了另一個域的應用, 雖然這兩個RSL是相同的, 但是需要下載兩次.
RSL通常會增加應用的啟動時間. 這是應用不管整個庫實際如何使用, 只是簡單地全部加載整個庫. 就這一點來說, RSL越小越好. 這與靜態鏈接庫的使用是不同的. 當你編譯一個Felx應用時, 編譯器只解開需要的組件. 一般來說, 庫的大小可以是任意的, 它只影響編譯時間而不會影響下載的時間.
如果在好幾個應用中使用相同的組件庫, 那么可以考慮合并這些庫, 形成一個RSL. 但是如果庫合并后, 每個應用只會用到其中的一小部分, 那么還不如多加載幾個小RSL更高效.
如果一些類重復打包在多個RSL中, 那么一定要注意同步更新的問題.
RSL不能應用在基類是Sprite或者MovieClip的純ActionScript項目中. 因為RSL需要基類知道如何加載RSL, 比如: Application或者SimpleApplication.
關于?framework.swc文件
framework.swc是一個標準的SWC文件. 缺省地它不能用作RSL. 整個framwork.swc文件不被鏈接到任何一個應用中. Flex編譯器只將那些應用用到的部分鏈接到生成最后的SWF文件. 比如: 如果一個應用只使用了Button, Panel和TextArea控件, 那么只有這幾個控件和它們的依賴項被編譯器鏈接.
幾乎所有的應用都需要framework.swc文件的一部分, 但是它并不適合作為RSL. 原因如上據說, RSL是整個鏈接, 不管實際使用多少的. 如果RSL包含了很多類, 而應用只使用了其中的一小部分, 那么這樣的加載方式并不是最合理的. 這樣使用會造成應用的啟動時間大大增加.
RSL的優點
下面的一個例子說明了將幾個的共享組件做成RSL的優點. 在這個例子中, 組件庫的大小是150K, 編譯后的應用的大小是100K.
?
使用了RSL, RSL只被下載一次. 那么合計下載量是350K, 節約了30%. 如果再添加第3個, 第4個應用的話, 每次都能150K的下載量.
一般來說, 在一個域中使用同一個RSL的應用越多, 那么好處就越大.
理解鏈接可以幫助你理解RSL是怎樣工作的. Flex編譯器支持靜態鏈接和動態鏈接. 靜態鏈接是最通常的方法. 但是動態鏈接使你借助于RSL來實現SWF文件的縮水以及應用的下載次數.
當你使用靜態鏈接時, 編譯器將應用中所有引用的類和依賴生成到最終的SWF文件中, 這個文件會比較大, 下載也會比較慢, 但是下載完畢后, 運行會比較快, 因為SWF文件中已經包含了所有的代碼.
如果你的應用中使用了類庫, 那么你需要使用類路徑或者是添加SWC文件. 如果是使用類路徑, 編譯器會將類路徑中用到的那部分類打包生成到SWF文件中. 如果是使用SWC文件, 編譯器會將整個SWC文件打包到SWF文件中.
動態鏈接是這樣的: 一個應用要使用的一部分類存在于一個外部的文件中, 運行時動態加載. 這樣的話, 主SWF文件可以小一些, 但是應用依賴于運行時加載的外部文件. RSL就是使用動態鏈接的.
如果想使用動態鏈接類, 需要把它們編譯成庫. 然后編譯器將庫中的內容從SWF文件剔除出去. 而且必須在編譯時提供鏈接檢查.
為指定哪些文件是動態鏈接的,需要使用外部庫路徑選項,外部選項或者外部加載編譯選項. 這些選項告訴編譯器從應用中去除此部分內容, 而預備在運行時調用. 外部選項為動態鏈接指定了單獨的類. 外部加載選項指定了一個XML文件, 描述了動態鏈接的類.
指定SL的外部資源的順序是非常關鍵的, 因為被其他類調用的基礎類必須被首先加載.
你還要用runtime-shared-libraries選項來指定RSL的位置.
你可以使用link-report這個編譯選項來查看應用的鏈接信息.
減小應用SWF文件大小的一個方法就是將一些共享的外部資源拆分出去, 成為一個獨立的文件, 這樣可以單獨地加載緩存到客戶端. 這些共享資源可以由多個應用在運行時進行加載, 但是傳遞到客戶端的動作只會發生一次. 這些共享文件被稱為運行時共享庫(Runtime Shared Libraries)或者簡寫為RSL.
如果你有多個應用而且這些應用共享一些核心組件或者類, 那么作為RSL,用戶只會唯一的一次加載這些資源. 只要應用在同一個域中, 這些應用共享同一個緩存的RSL, 這樣應用文件的大小就減小了. 使用RSL的應用越多, 效果越好, 如果只有一個應用, 總的文件大小不但不減小,反而會增大.
你既可以使用Flex Builder通過項目選項來創建Flex的Library項目,也可以使用compc這樣的命令行. 編譯好RSL以后, 可以在編譯應用時把Library的位置傳遞給編譯器.
下面是適合使用RSL的典型用例: ??? * 大型應用, 需要使用通用組件庫加載多個小型應用. 最頂級的應用和下級應用可以共享存儲在RSL中的組件.
??? * 在一個服務器上的使用通用組件庫的系列應用. 當用戶操作第一個應用時, 用戶下載應用的SWF文件和RSL. 當操作第二個應用時, 用戶就只需要下載應用本身的SWF文件就行了. ???? ??? * 一個獨立的應用使用RSL的意義在于: 如果這個應用本身會頻繁的修改, 而有一部分組件是極少改動的. 在這種情況下, 使用RSL的好處是: 組件下載一次, 而應用可以多次下載.
?
總結起來需要注意的原則就是:盡量在編譯的階段發現錯誤,因為這時發現并解決錯誤遠遠要比在運行時出錯解決起來容易的多。可是實際情況中很多人經常會違反這一原則,下面是我列舉的10個技巧:
1) 永遠不要使用'Object' 來存儲數據. 因為這是一種繞開編譯器檢查的做法,完全不符合面向對象的思想。如果要用Hashmap或者相應的數組,那么可以用Dictionary。否則,請自已定義一個類,而不要使用Object來作為數據的存儲器。
2) 不要用Object來作為對象的類型。這是欺騙編譯器的方法。如果必須這樣用,最好在存取屬性或者調用函數時,先進行強制性的類型轉換,至少這是給編譯器的一個提示,也幫助其他人理解你的代碼。
3) 也不要用*類型。
4) 不要將ActionScript的類聲明為動態。
5) 注意Application.application (和其他的無類型的框架屬性). 這個屬性有一些古怪.??他應該是Applicaton類型的,因為他指向的實例必須是Application的子類. 但實際上他的類型是'Object', 無法應用編譯時的檢查。如果你一定要用,最好也進行類型的強制性轉換。:
MyApplication( Application.application ).functionCall();
6) 封裝你的Xml。使用Xml與Server進行數據的交互非常方便,但是盡量避免使用Xml作為核心數據模型。從服務器收到數據后,盡量把Xml轉換為強類型的對象模型。在Flex應用內部使用Xml是繞開編譯器的作法。
7) 不要使用DynamicEvent.
8) 不要使用mx:Model。如上所述,請盡量使用自定義的強類型的類.
9) 不要使用Cairngorm中的data屬性,而應該繼承擴展CairngormEvent來傳遞數據。
10) 不要把編譯器的嚴格模式關掉
|