2011年5月7日 星期六

Flex4 Application(一):SystemManager、SystemManager.application、 topLevelApplication之間關係

Flex 4中的一個變更:
Flex3中Application裡的屬性application這個屬性在Flex4中被拿掉了,改由 FlexGlobalse這各類管理,由FlexGlobalse的topLevelApplication屬性代替原本的appliction,topLevelApplication這是一個靜態的屬性。

什麼是topLevelApplication?
的ApplicationDomain中運行的第一個應用程序是頂層應用程序在頂層應用程序的構造函數中將此屬性設置為對頂層應用程序的引用每個 ApplicationDomain中都有其自己的topLevelApplication,這個topLevelApplication通常就是一支SWF,在Flex中這支SWF通常會是一個Application的實體,在一個ApplicationDomain中可能會有多個SWF存在,但只會有一個負責管理所有應用程式的最上層Application,這個管理者就是topLevelApplication。


adobe技術手冊中的圖示如下:

















範例:在一SWF中利用Loader讀取另一支SWF,在loader()第二個參數使用預設null。
請參考LoaderI與LoaderContext
  • loader()第二參數為null時,將使用Loader所在的Application的ApplicationDomain。
程式碼Hero_Test.mxml:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
  xmlns:s="library://ns.adobe.com/flex/spark"
  xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="1280" minHeight="780"
  applicationComplete="application1_applicationCompleteHandler(event)"
  pageTitle="Hero_Test"
  >
<fx:Script>
<![CDATA[
import mx.core.FlexGlobals;
import mx.core.UIComponent;
import mx.events.FlexEvent;
import mx.managers.SystemManager;

 private var _loader:Loader;
 private var _request:URLRequest;
 private var _systemManager:SystemManager;
 protected function application1_applicationCompleteHandler(event:FlexEvent):void
{
 initLoader();
 deployLoader();
 startLoader();
 btn.addEventListener(MouseEvent.MOUSE_DOWN , onDown);
}
 private function initLoader():void
{
  _loader = new Loader();
  _loader.contentLoaderInfo.addEventListener(Event.COMPLETE , onLoaderComplete);
  _request = new URLRequest('./swf/ByLoaderSWF.swf');
}
private function deployLoader():void
{
  uic.addChild(_loader);
  this.box.addElement(uic);
}
private function startLoader():void
{
  _loader.load(_request);
}
private function onLoaderComplete(e:Event):void
{
 _systemManager = _loader.content as SystemManager;
 changedColorBtn.addEventListener(MouseEvent.MOUSE_DOWN , onChangeColor);
  uic.width = _loader.content.width;
  uic.height= _loader.content.height;
}

private function onChangeColor(e:MouseEvent):void
{
 var color:uint = Math.round(Math.random()* 0xFFFFFF);
  _systemManager.application['setByLoaderSWFbackgroud'](color);
  info.text = color.toString();
}

private function onDown(e:MouseEvent):void
{
 var o:Object = FlexGlobals.topLevelApplication;
 info.text ="";
 info.text = "this = " + this + '\n\n';
  info.text += 'topLevelApplication = ' + o.toString()+'\n\n';
  info.text += 'systemManager = ' + this.systemManager + '\n\n';
}

]]>
</fx:Script>
<s:HGroup id="box">
<s:VGroup>
<s:Panel title="Hero_Test">
<s:TextArea id="info" editable="false" width="420"/>
</s:Panel>
<s:Label text="print Hero_Test資訊"/>
<s:Button id="btn" label="print"/>
<s:Button id="changedColorBtn" label="changeColor"/>
</s:VGroup>
<mx:UIComponent id="uic"/>
</s:HGroup>
</s:Application>


程式碼ByLoaderSWF.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
  xmlns:s="library://ns.adobe.com/flex/spark"
  xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="600" minHeight="200"
  applicationComplete="application1_applicationCompleteHandler(event)"
  pageTitle="ByLoaderSWF"
  backgroundColor="0xA1FF8F"
  >
<s:layout>
<s:BasicLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import mx.controls.ProgressBar;
import mx.core.FlexGlobals;
import mx.events.FlexEvent;
import mx.managers.SystemManager;
import mx.preloaders.DownloadProgressBar;

protected function application1_applicationCompleteHandler(event:FlexEvent):void
{
 Security.allowDomain("*");
 btn.addEventListener(MouseEvent.MOUSE_DOWN , onDown);
}
private function onDown(e:MouseEvent):void
{
 var _topLevelApplication:Object = FlexGlobals.topLevelApplication;
 info.text ="";
 info.text = "this = " + this + '\n\n';
 info.text += 'topLevelApplication = ' + _topLevelApplication.toString()+'\n\n';
 info.text += 'systemManager = ' + this.systemManager + '\n\n';
}

public function setByLoaderSWFbackgroud(color:uint):void
{
  this.setStyle("backgroundColor",color);
}

]]>
</fx:Script>
<s:VGroup>
<s:Panel title="ByLoaderSWF資訊看板">
<s:TextArea id="info" editable="false" width="450"/>
</s:Panel>
<s:VGroup>
<s:Label text="Print ByLoaderSWF資訊"/>
<s:Button id="btn" label="print"/>
</s:VGroup>
</s:VGroup>
</s:Application>


將這兩支mxml編譯成SWF,並將發佈的的資料放置Web Server中運行。

  • 注意,Loader在load SWF時,無法在flashBuilder中直接執行運作,因為Loader SWF不可在本機上執行,這是FlashPlayer的安全機制,將其放置Web Server中運行即可。










我們可以看到ByLoaderSWFtopLevelApplication是指向Hero_Test。



而我們可以在Hero_Test中呼叫ByLoaderSWF的public function 。

呼叫ByLoaderSWF的setByLoaderSWFbackgroud(color:uint)方式如下:

//在Loder的contentLoaderInfo讀取完畢發出Complete時將Loader的content轉成SystemManager。
private var _systemManager:SystemManager;

private function onLoaderComplete(e:Event):void
{
_systemManager = _loader.content as SystemManager;
changedColorBtn.addEventListener(MouseEvent.MOUSE_DOWN , onChangeColor);
}
//在Button被按下後呼叫,利用_systemManager來呼叫setByLoaderSWFbackgroud(color:uint)


private function onChangeColor(e:MouseEvent):void
{
var color:uint = Math.round(Math.random()* 0xFFFFFF);
_systemManager.application['setByLoaderSWFbackgroud'](color);
info.text = color.toString();
}


什麼是SystemManager?

  • SystemManager是應用程式的根(root)。
  • SystemManager是MovieClip的子類,有兩個影格。
  • SystemManager在第一個影格是預載器,在此會載入。
  • SystemManager在第二個影格會開始建立主要應用程式的實體。
  • SystemManager有個application屬性,會指向Application的實體。
  • application這個屬性在第二影格建立屬性前都會是null,也就是說SystemManager是一支應用程式中最先建立的然後才是建立Flex中主要應用程式的類別(如Application)。

systemManager中有一個屬性application其實就是Application的instance,而在這裡_systemManager中其實就是ByLoaderSWF的SystemManager。

關於this對象、SystemManager對象、SystemManager.application在ByLoaderSWF單獨執行下的追蹤結果。