2012-06-08 77 views
0

我一直在尋找谷歌,但我找不到一個好的答案。 我正在使用Flex 4並使用模塊構建一個空氣應用程序(因爲這是一個大項目,所以會有很多模塊)。 我設法加載模塊在由popupmanager調用的titlewindow中,但是當titlewindow被關閉時,模塊不會被卸載(garbaged) - 我在flasbuilder中使用profiler來檢查這個模塊。Flex 4 AIR APP卸載模塊的正確方法

這是我的代碼,我需要知道如果我在項目中使用模塊之前正在使用模塊進行正確的方向。

感謝所有

Main APP: MXML 

<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
        xmlns:s="library://ns.adobe.com/flex/spark" 
        xmlns:mx="library://ns.adobe.com/flex/mx" 
        xmlns:tblusersservice="services.tblusersservice.*" 
        xmlns:valueObjects="valueObjects.*" 
        xmlns:tbluserservice="services.tbluserservice.*" 
        width="100%" height="100%" applicationComplete="checkForUpdate()" preinitialize="nativeWindow.maximize();" currentState="login"> 

<fx:Script source="includes/_loadtracker.as"/> 



<s:Panel id="panelmain" includeIn="mainmenu" left="5" width="100%" height="100%" resizeEffect="Resize" title="Main menu"> 

    <s:Image id="companymenu" right="15" top="130" width="118" height="93" buttonMode="true" 
      click="loadmodule('mod_company', 'Company Information', 931, 446);" source="assets/company.png" useHandCursor="true"/> 


</s:Panel> 



</s:WindowedApplication> 




_loadtracker.as: 

// ActionScript file 
import flash.filesystem.*; 
import flash.events.ErrorEvent; 
import flash.events.MouseEvent; 
import flash.events.Event; 
import flash.display.*; 
import air.update.ApplicationUpdaterUI; 
import air.update.events.UpdateEvent; 
import mx.controls.Alert;  
import mx.managers.PopUpManager; 
import mx.rpc.events.ResultEvent; 
import spark.components.TitleWindow; 
import valueObjects.*; 
import flash.desktop.NativeApplication; 



// Open the pop-up window. 
private function loadmodule(modname:String, modtitle:String, modwidth:int, modheight:int):void { 
// Create a non-modal TitleWindow container. 
settings.moduletoload = modname; 
var titleWindow:TitleWindow= 
    PopUpManager.createPopUp(this, showmodules, true) as TitleWindow; 
titleWindow.title = modtitle; 
titleWindow.width = modwidth; 
titleWindow.height = modheight + 35; 
    PopUpManager.centerPopUp(titleWindow); 
} 





showmodules.mxml 

<s:TitleWindow xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx" width="400" height="400" creationComplete="initModule()" close="handleCloseEvent()"> 

<fx:Script> 
    <![CDATA[ 

     import mx.controls.Alert; 
     import mx.core.IVisualElement; 
     import mx.events.ModuleEvent; 
     import mx.managers.PopUpManager; 
     import mx.modules.IModuleInfo; 
     import mx.modules.ModuleManager; 
     import mx.rpc.events.ResultEvent; 
     import services.tbluserservice.*; 

     public var info:IModuleInfo; 
     public var modclosed:Boolean = false; 

     private function initModule():void { 
      this.addEventListener("foobar", handleCloseEventmodule); 

      info = ModuleManager.getModule("/modules/"+settings.moduletoload+".swf"); 
      info.addEventListener(ModuleEvent.READY, modEventHandler);   

      info.load(null, null, null, moduleFactory); 
     } 

     /* Add an instance of the module's class to the display list. */   
     private function modEventHandler(e:ModuleEvent):void { 

      this.addElement(info.factory.create() as IVisualElement); 
     } 

     // Handle the close button and Cancel button. 
     public function handleCloseEvent():void { 

       PopUpManager.removePopUp(this); 
       info.unload(); 
       info.release(); 
       info = null; 

     } 

    ]]> 
</fx:Script> 

<fx:Declarations> 
    <!-- Place non-visual elements (e.g., services, value objects) here --> 
</fx:Declarations> 
</s:TitleWindow> 




mod_company.mxml 

<s:Module xmlns:fx="http://ns.adobe.com/mxml/2009" 
     xmlns:s="library://ns.adobe.com/flex/spark" 
     xmlns:mx="library://ns.adobe.com/flex/mx" 
     xmlns:tblcompanyservice="services.tblcompanyservice.*" 
     xmlns:valueObjects="valueObjects.*" 
     width="931" height="446" 
     creationComplete="LoadData()"> 
<fx:Script> 
    <![CDATA[ 
     import mx.events.FlexEvent; 

     protected function dataGrid_creationCompleteHandler(event:FlexEvent):void 
     { 
      getAllTblcompanyResult.token = tblcompanyService.getAllTblcompany(); 
     } 

    ]]> 
</fx:Script> 

<fx:Script source="../includes/_company.as"/> 

<fx:Declarations> 
    <tblcompanyservice:TblcompanyService id="tblcompanyService" 
             fault="Alert.show(event.fault.faultString + '\n' + event.fault.faultDetail)" 
             showBusyCursor="true"/> 
    <s:CallResponder id="getTblcompanyByIDResult" fault="Alert.show(event.fault.faultString + '\n' + event.fault.faultDetail)" 
        result="tblcompany = getTblcompanyByIDResult.lastResult as Tblcompany"/> 
    <valueObjects:Tblcompany id="tblcompany"/> 
    <s:CallResponder id="updateTblcompanyResult"/> 
    <s:CallResponder id="getAllTblcompanyResult"/> 
    <!-- Place non-visual elements (e.g., services, value objects) here --> 
</fx:Declarations> 
<s:Label x="81" y="41" text="COMPANY NAME"/> 
<s:Label x="81" y="71" text="ADDRESS"/> 
<s:Label x="83" y="131" text="CITY"/> 
<s:Label x="83" y="161" text="STATE"/> 
<s:Label x="83" y="191" text="ZIP"/> 
<s:Label x="83" y="221" text="COUNTRY"/> 
<s:Label x="582" y="41" text="TELEPHONE"/> 
<s:Label x="582" y="71" text="FAX"/> 
<s:Label x="582" y="102" text="WATTS"/> 
<s:Label x="83" y="276" text="OWNER"/> 
<s:Label x="83" y="324" text="LOGO PATH"/> 
<s:TextInput id="fNameTextInput" x="185" y="32" width="323" text="{tblcompany.fName}"/> 
<s:TextInput id="faddressTextInput" x="185" y="62" width="256" text="{tblcompany.faddress}"/> 
<s:TextInput id="faddress2TextInput" x="185" y="92" width="256" text="{tblcompany.faddress2}"/> 
<s:TextInput id="fcityTextInput" x="185" y="122" width="256" text="{tblcompany.fcity}" textAlign="left"/> 
<s:TextInput id="fstateTextInput" x="185" y="152" width="256" text="{tblcompany.fstate}"/> 
<s:TextInput id="fzipTextInput" x="185" y="182" width="81" text="{tblcompany.fzip}"/> 
<s:TextInput id="fcountryTextInput" x="185" y="212" width="256" text="{tblcompany.fcountry}"/> 
<s:TextInput id="ftelTextInput" x="701" y="32" text="{tblcompany.ftel}"/> 
<s:TextInput id="ffaxTextInput" x="701" y="62" text="{tblcompany.ffax}"/> 
<s:TextInput id="fwattsTextInput" x="701" y="92" text="{tblcompany.fwatts}"/> 
<s:TextInput id="fownerTextInput" x="185" y="266" width="418" text="{tblcompany.fowner}"/> 
<s:TextInput id="flogopathTextInput" x="185" y="314" width="644" text="{tblcompany.flogopath}"/> 
<s:TextInput id="fidTextInput" x="224" y="379" text="{tblcompany.fid}" visible="false"/> 
<s:Button id="button" x="79" y="379" label="Save" click="button_clickHandler(event)"/> 
<s:DataGrid id="dataGrid" x="158" y="242" 
      creationComplete="dataGrid_creationCompleteHandler(event)" requestedRowCount="4"> 
    <s:columns> 
     <s:ArrayList> 
      <s:GridColumn dataField="fid" headerText="fid"></s:GridColumn> 
      <s:GridColumn dataField="fName" headerText="fName"></s:GridColumn> 
      <s:GridColumn dataField="fowner" headerText="fowner"></s:GridColumn> 
      <s:GridColumn dataField="faddress" headerText="faddress"></s:GridColumn> 
      <s:GridColumn dataField="faddress2" headerText="faddress2"></s:GridColumn> 
      <s:GridColumn dataField="fcity" headerText="fcity"></s:GridColumn> 
      <s:GridColumn dataField="fzip" headerText="fzip"></s:GridColumn> 
      <s:GridColumn dataField="fstate" headerText="fstate"></s:GridColumn> 
      <s:GridColumn dataField="fcountry" headerText="fcountry"></s:GridColumn> 
      <s:GridColumn dataField="ftel" headerText="ftel"></s:GridColumn> 
      <s:GridColumn dataField="ffax" headerText="ffax"></s:GridColumn> 
      <s:GridColumn dataField="fwatts" headerText="fwatts"></s:GridColumn> 
      <s:GridColumn dataField="flogopath" headerText="flogopath"></s:GridColumn> 
      <s:GridColumn dataField="femail" headerText="femail"></s:GridColumn> 
     </s:ArrayList> 
    </s:columns> 
    <s:typicalItem> 
     <fx:Object faddress="faddress1" faddress2="faddress21" fcity="fcity1" 
        fcountry="fcountry1" femail="femail1" ffax="ffax1" fid="fid1" 
        flogopath="flogopath1" fName="fName1" fowner="fowner1" fstate="fstate1" 
        ftel="ftel1" fwatts="fwatts1" fzip="fzip1"></fx:Object> 
    </s:typicalItem> 
    <s:AsyncListView list="{getAllTblcompanyResult.lastResult}"/> 
</s:DataGrid> 
</s:Module> 




_company.as 


// ActionScript file 
//import flash.desktop.NativeApplication; 
import flash.events.MouseEvent; 
import flash.events.Event; 
import mx.controls.Alert; 
//import mx.core.Application; 
//import mx.core.mx_internal; 
import services.tblcompanyservice.*; 
import valueObjects.*; 

protected function LoadData():void { 
getTblcompanyByIDResult.token = tblcompanyService.getTblcompanyByID(parseInt("1")); 
} 

protected function button_clickHandler(event:MouseEvent):void { 
tblcompany.fid = parseInt(fidTextInput.text); 

tblcompany.fName = fNameTextInput.text; 
tblcompany.fowner = fownerTextInput.text; 
tblcompany.faddress = faddressTextInput.text; 
tblcompany.faddress2 = faddress2TextInput.text; 
tblcompany.fcity = fcityTextInput.text; 
tblcompany.fzip = fzipTextInput.text; 
tblcompany.fstate = fstateTextInput.text; 
tblcompany.fcountry = fcountryTextInput.text; 
tblcompany.ftel = ftelTextInput.text; 
tblcompany.ffax = ffaxTextInput.text; 
tblcompany.fwatts = fwattsTextInput.text; 
tblcompany.flogopath = flogopathTextInput.text; 
tblcompany.femail = ""; 
updateTblcompanyResult.token = tblcompanyService.updateTblcompany(tblcompany); 
//Alert.show("Modifications saved"); 
//this.dispatchEvent(new Event("foobar", true)); 
} 

回答

0

卸載Flex模塊具有historically been problematic。 Flex 4和我認爲4.5開始削弱潛在問題,讓我們的生活更輕鬆。

當您的主應用程序中的某些內容維護對模塊中某個對象的引用時,它將阻止您的模塊卸載。有很多方法可以發生。由於Flex的工作方式,Flex可能仍然會導致一些問題。但主要的麻煩已經被緩解了(儘管我確定你使用Flex 4.5)。

現在想想這件事你絕對明智。不是選擇使用模塊,而是確保它們正在卸載。

我鏈接到的文章是來自Flex SDK開發人員的舊文章,而其中一些問題可能不再存在,這些概念應該是有啓發性的。

編輯

在進一步審查,僅是跳出我的事情之一似乎值得看的:

  • 你的模塊中的腳本標籤可以有風格可以在同一個問題介紹(也可能是一個紅鯡魚)。這個想法是,使用這個腳本的第一個類可能與Flex內部的腳本永久關聯。如果該類是一個模塊,它將永遠不會卸載。作爲測試,您也可以嘗試在WindowedApplication類中聲明腳本標記(即使它未被使用)。

我想過的另一件事是在您的視圖中可綁定變量。但在進一步的審查中,我看不到這些可能導致內存泄漏。

+0

我使用flex 4.6 actualy。我也是新來flex,你是否看到我的代碼中可能導致這種情況的東西?謝謝 – gfbaggio

+0

Doh,我怎麼能忘記4.6(在度假)!也許模塊中有些東西可以查看(編輯我的答案)。 –

+0

我刪除了腳本標記並將所有AS包含在相同的代碼中。進行了如下更改 – gfbaggio

0

我認爲問題在於您每次創建一個新的TitleWindow,並且TitleWindow將事件偵聽器添加到通過模塊加載器和never removes it加載的模塊中。從理論上講,PopupManager.removePopup也應該每次取消引用TitleWindow,但是,老實說,將這個功能編寫爲全局/靜態類的人可能不能被信任遵守其他地方的良好實踐,因此您應該可以使用F3查看PopupManager上的代碼,並確保它刪除它添加的任何事件偵聽器,並將對標題窗口的引用歸零。由於它是一個靜態類,一旦有事與它交談,如果它沒有正確解引用它們,它們將堅持應用程序的生命。

接下來,即使您已經加載了一個模塊,也是手動創建了模塊的實例。你需要做一些事情(除去你的事件監聽器)試圖放開加載器,但你永遠不會釋放手動創建的實例。爲了簡化一些事情,可以嘗試添加已加載的模塊,而不是創建額外的模塊。

另一個建議是而不是使用視圖元素來代替數據存儲。所以,而不是綁定到VO,當你得到它從你的領域填充。當有任何變化時,根據VO的值更新VO。這會導致更多的代碼,但首先,您總是知道您的數據是最新的。另一方面,如果需要,數據可以獨立於視圖而傳播。但是這是一件可以幫助你消除綁定將VO保存在內存中的可能性。

還有一些事情會在代碼周圍產生一絲淡淡的稗味,這也可能是問題的根源。例如,你的標題窗口子類似乎有一個設置的參考,即使你還沒有給出它。這表明設置實際上是一個靜態類,並且您忽略了類應以大寫字母開頭的命名約定。更重要的是,如果你有像這樣的後臺渠道進行溝通,那麼就沒有辦法看你的代碼,並確定你沒有發生什麼事情,在某種程度上你已經給出了設置參考它所持有的東西到。

你也有什麼似乎是一個未聲明的變量,modulefactory,但我認爲這可能是一個命名錯誤的類,它與TitleWindow生活在同一個包中(所以沒有import語句)。快速的建議:如果你想在論壇上獲得幫助,遵循命名規則將使希望幫助你解開你所做的事情的人更容易。在這種情況下,可能會有一些地方出現「非法」功能,妨礙了最佳實踐OOP通信,並且由於您命名的方式而不容易識別。但最終,我認爲如果你只下載到模塊的一個副本並刪除了事件監聽器,那麼你應該可以放棄你的模塊,它應該讓你釋放VO。

+0

我試圖在我的主應用程序中包含所有的remoteobject,而不是將它們放在模塊中,但是我還沒有找到任何有關tomdo的例子。你能幫助我嗎?謝謝 – gfbaggio

+0

這裏有幾篇文章討論了從使用依賴注入框架來處理這個問題的VO進行重構,這是一個類似的概念:http://www.developria.com/2010/06/robotlegs -for-framework-beginn.html http://www.developria.com/2010/05/refactoring-with-mate.html。以下是原始http://flexdiary.blogspot.com/2009/01/lazy-loading-tree-example-file-posted.html,其中服務代碼至少是模型的一部分,而不是視圖。 –