FlexViewer學習資料,希望對初學者有幫助(轉)

1 Sample Flex Viewe架構

1.1 架構介紹

Sample Flex Viewer框架的構建有助於開發和部署針對GeoWeb的應用程序,使得能夠充分的發揮服務器端的空間服務的能力。服務器端的服務通過ArcGIS服務器和ArcGIS在線數據提供。如下圖所示,地球空間信息服務可以由工作在軟件即服務方式的伺服機提供商獲得,比如ArcGIS在線數據庫,ArcGIS服務器或者是像GeoRSS反饋,KML文件庫以及JSON/REST數據等網絡數據源。基於Sample Flex Viewer框架開發的應用程序所消耗的數據可以由服務器端提供,也可以是從移動設備運行動態生成的數據,如現場項目師的筆記本電腦或智能手機。

圖1  地球空間信息服務

1.2 Sample Flex Viewer實例的生命週期

一個Sample Flex Viewer框架的實例從開始應用程序的設計到用戶看到帶微件的界面經歷了一個簡單的生命週期。期間主要的5個事件如下:1.Flash播放器從加載和運行容器文件開始一個Sample Flex Viewer框架的應用程序。2.這個Flex Viewer容器再從網絡服務器加載XML格式的配置文件和皮膚文件並應用於整個應用程序。3.在配置文件的基礎上,Flex Viewer容器會從ArcGIS在線數據和ArcGIS9.3服務器下載相關的地圖信息,然後會從配置文件中加載並且在控制條上顯示菜單和來自配置文件的標記信息。 4.Flex Viewer容器的微件管理器會從XML配置文件指定的URLs下載並加載相關的微件文件(一般是swf文件)。 5.用戶利用微件來實現各種業務邏輯。

1.3 Sample Flex Viewer容器

Sample Flex Viewer容器使設計人員能夠擺脫地圖管理、地圖導航、應用配置、組件間的通信、數據管理等繁重複雜的編程工作,專注於核心業務功能開發,尤其是那些利用ERSI公司的ArcGIS技術的網絡應用開發人員。而且只需要在Flex Viewer應用程序的配置文件中增加配置項,就可以將功能以widget的形式快速部署到已有的Flex Viewer應用中。Sample Flex Viewer容器由一系列高內聚、低耦合組件組成(如下圖所示)。容器會把關注的任務交給相應的組件去完成。這種設計方法不但簡化了代碼維護和定製,而且縮小了模塊編寫過程中產生的阻力。

圖2  Sample Flex Viewer容器整體架構

1.4 理解Widget編程模型

經過編譯的widget是一個獨立的SWF(Flash)文件,可在Flex Viewer程序中共享、移動和配置。Widget封裝了一系列獨立並且針對性很強的業務邏輯,用戶可以在其中執行任務。在一個面向服務的環境下,一個widget可以代表是一種服務或者是一套相關的服務,用戶可以很明瞭的用它來執行一個業務功能。widget不僅爲用戶提供了可視化的界面,也能夠連到服務器端的資源,像是來自ArcGIS服務器或是ArcGIS在線數據庫的地圖服務。一系列相互關聯的widget加上清晰定義好的業務操作流程組成了業務解決方案。而且這樣的方案可以應用於企業級的業務進程中。輕量級的Flex Viewer Widget編程模型使得開發人員可以輕易定製widget,避免了將widget整合到Flex Viewer應用程序中所需的底層代碼開發。widget編程模型包含了兩個ActionScript類(其中一個後爲mxml類)以及兩個ActionScript接口。後面一個章節將會講述如何使用這些類以及接口的相關細節。

IBaseWidget Interface (IBaseWidget.as) 這個接口定義了WidgetManager管理微件的通信方法。而基礎widget類BaseWidget則要來實現這個接口。

BaseWidget Class (BaseWidget.as) 這個是widget的基類,所有的微件都要繼承這個類。通過擴展BaseWidget這個父類,WidgetManager會驗證所有擴展了BaseWidget的MXML或AS類是否爲可部署的微件。另外,擴展了BaseWidget的類能夠被編譯爲一個獨立的SWF文件。每個Flex Viewer框架下的微件必須繼承BaseWidget這個父類。

IWidgetTemplate (IWidgetTemplate.as) 這個接口定義了widget模板能夠被BaseWidget識別所需要的一般操作。是使用一個widget模板還是使用內置的widget模板通常是可選的。內置的WidgetTemplate類要實現IWidgetTemplate這個接口。

WidgetTemplate (WidgetTeamplate.mxml) 這是一個內置的widget模板,它是一個爲widget提供基本的佈局和行爲的用戶界面組件。這些佈局和行爲包括一個標準的窗口面板,帶有自定義圖標按鈕的標題欄等組件。使用這類模板,使得widget開發者能夠把更多的時間和精力放在覈心的業務需求上面。內置的widget模板通常也能被widget開發者用來定製屬於自己的widget模板,前提是必須實現IWidgetTemplate這個接口。

1.5  Widget命名習慣

Widget 類: 一般來講一個widget類得有”Widget”這樣一個後綴,比如”NameWidget.mxml” ;Widget的配置文件: 一個好的習慣就是,將widget的配置文件取相同的文件名,只是擴展名採用xml,比如NameWidget.xml。

2 開發一個widget

儘管前面兩個章節講述了兩種widget項目開發的途徑,但其實它們實際的核心功能開發的原理是一樣的。這一章我們會用第一種開發方式來做更深入的講解。我們先假設widge的開發員很熟悉Flex的開發環境。

2.1 使用WidgetTemplate模板

在接着2.1節所創建的一個widget文件MyFirstWidget.mxml講,它的代碼如下:

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

<BaseWidget xmlns="com.esri.solutions.flexviewer.*"xmlns:mx="http://www.adobe.com/2006/mxml>

</BaseWidget>

在widget編程模型匯中的WidgetTemplate模板提供的默認widget窗口給出了一套很豐富的內置組件。使用這個模板添加兩行如下代碼:

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

<BaseWidget xmlns="com.esri.solutions.flexviewer.*"xmlns:mx="http://www.adobe.com/2006/mxml>

<WidgetTemplate id="widgetTempalte">

</WidgetTemplate>

</BaseWidget>

按照如下幾個步驟進行配置和部署就能看到運行結果:

第一步:在config.xml中添加創建的widget;打開config.xml文件添加下面幾行代碼到<widget>標記塊,你可以爲創建的widget使用自己的圖標,可以是40×40的一個png圖像文件,或者gif、jpg文件。

<widget label  = "My First Widget"

icon   = " com/esri/solutions/flexviewer/assets/images/icons/i_globe.png"menu   = "menuWidgets"

config = "";>

mywidgets/MyFirstWidget.swf

</widget>

第二步:保存文件並編譯整個項目;具體編譯方法參考上一章內容。

第三步:運Flex Viewer應用程序;右鍵項目中的index.mxml文件並點擊Run Application。

第四步:從工具菜單,點擊MyFirstWidget

下面將會加載並輸出顯示你的widget。

圖3  My First Widget菜單

前面給widget添加的兩行代碼,是的當前的widget能夠有一個標準的視圖和感官效果,並且能夠有一些基本功能,比如能夠最小化,最大化以及關閉的效果。而且,當前的widget還可以和Sample Flex Viewer進行內部通信。接下來就可以在WidgetTemplate模板上添加自己的UI元素並且寫自己的業務邏輯了。

2.2 獲取地圖信息

Sample Flex Viewer是一個基於地圖服務開發的應用。一旦這個應用被初始化,通常widget能夠從ArcGIS的地圖服務上連接到一個或者多個地圖資源。在基類BaseWidget中定義了一個公共屬性map,一個widget被加載以後widget管理器就會把當前激活的一個地圖對象傳給這個widget。這個widget的map屬性來自com.eari.ags.Map類,繼承於ArcGIS API for Flex。你就能夠訪問到ArcGIS提供的所有的地圖參數。widget的代碼寫起來就像一個常規的ArcGIS Flex的應用程序一樣。這裏有一個例子,在MyFirstWidget中添加了一個按鈕。當點擊這個按鈕時,地圖就會自動的以當前設置的座標爲中心。在編譯並且配置完widget後重新運行Sample Flex Viewer應用程序,如圖:

圖4  My First Widget微件圖

2.3 在地圖上顯示widget數據

添加圖層

建議爲每一個新創建的widget添加一個圖層,這個圖層能夠被添加到地圖服務中去,具體是在widgetConfigLoaded這個事件處理器中的init方法進行相關初始化操作。當所有的widget的配置信息加載完畢並且待命時就會傳出一個widgetConfigLoaded事件。相應代碼如下:

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

<BaseWidget x="600" y="300" xmlns:esri="http://www.esri.com/2008/ags" xmlns="com.esri.solutions.flexviewer.*"xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:mxeffects="com.adobe.ac.mxeffects.*" xmlns:widgets="com.esri.solutions.flexviewer.widgets.*"widgetConfigLoaded="init()" >

<mx:Script>

<![CDATA[

 

private function init():void

{

graphicPointSym new PictureMarkerSymbol(widgetIcon, 30, 30)

graphicsLayer = newGraphicsLayer(); graphicsLayer.symbol= graphicPointSym;map.addLayer(graphicsLayer);

 

一旦添加了圖層,你接下來就能使用標準的ArcGIS API for Flex中的各個方法來給圖層加上各種圖形元素。當點擊open/minimize的圖標時打開/關閉widget圖層。WidgetTemplate模板設置了兩個窗口狀態事件:widgetOpened以及widgetClosed事件。他們都是擴展於flash.events.Event這個類。你可以使用這兩個事件來同步同步圖層的可見性。在這個例子裏,我們先添加兩個事件處理器到WidgetTemplate模板:

<WidgetTemplate id="wTemplate"widgetClosed="widgetClosedHandler(event)"widgetOpened="widgetOpenedHandler(event)">

private function widgetClosedHandler(event:Event):void

{

graphicsLayer.visible false;

}

 

 

private function widgetOpenedHandler(event:Event):void

{

graphicsLayer.visible true;

}

2.4 從地圖接收數據(通過單擊,畫線等操作實現)

對於GIS網絡應用,除了可視化數據這個特殊用途外,地圖還是一個允許用戶收集並且處理地圖數據的數據源。或許在用戶與地圖進行交互的過程中,我們創建的widget需要接收如點和直線或多邊形這一類的數據來進行處理。那麼Sample Flex Viewer以及widget編程模型就能夠用微件通過內置的setMapAction方法來請求或是接收這一類的地圖數據。下面這段代碼展示瞭如何激活畫圖工具來追蹤用戶在地圖上面的點擊操作:

 

private function activateTool():void

{

setMapAction(Draw.POINT, "Click Point", drawEnd);

}

private function drawEnd(event:DrawEvent):void

{

var geom:Geometry = event.geometry;

var pt:MapPoint = geom as MapPoint

Alert.show("Click location: " + pt.x + ", " + pt.y);

}

在上面的示例中,點擊widget中的按鈕會調用activeTool()方法。當一個指定的任務需要用戶點擊widget上的按鈕時,程序就能夠隨時從地圖上獲取一個點的座標信息。用戶下一步需要做的就是點擊地圖上任意位置,然後widget就能夠接收這個點擊行爲傳送的點信息。具體由一個回調函數drawEnd()傳回參數到setMapAction()方法來實現具體操作。

setMapAction方法

公共方法setMapAcion定義在BaseWidget類裏(在BaseWidget.as文件中),這樣所有繼承該類的widget就能夠自動繼承這個特性。該方法定義如下:public function setMapAction(action:String, status:String, callback:Function):void,其中參數:

action: 這個字符串標記表示ArcGIS API相應的畫圖工具被激活。下面列出的是ArcGIS Flex API提供的能夠用來訪問各種畫圖工具的字符串標記:

extent   (Draw.EXTENT) point   (Draw.MAPPOINT) line  (Draw.LINE) polyline       (Draw.POLYLINE) polygon (Draw.POLYGON)

multipoint    (Draw.MULTIPOINT)

freehandpolyline       (Draw.FREEHAND_POLYLINE)

freehandpolygon       (Draw.FREEHAND_POLYGON)

status:在控制條的狀態欄顯示的文本文字;

callback:畫圖操作完成後Map Manager回調的函數。

2.5 在widget中控制導航

當開發一個widget時,爲了能夠全屏顯示,放大或是縮小地圖,往往在用例中會需要控制地圖的導航。比如,當一個widget被關閉後,你需要關閉相應的圖層,並且使得地圖處於默認的全屏狀態。BaseWidget類提供了一個public方法setMapNavigation用來進行這些操作。代碼如下:

<WidgetTemplate id="wTemplate" widgetClosed="widgetClosedHandler(event)"

private function widgetClosedHandler(event:Event):void

{

graphicsLayer.visible false;

setMapNavigation(Navigation.PAN, “Pan Map”);

}

在上面的代碼裏,我們給WidgetTemplate這個模板一個事件處理器來相應widget關閉這個事件。在widgetClosedHandle處理器內部,public方法setMapNavigation被調用來將地圖的導航顯示爲全屏狀態。

setMapNavigation方法在BaseWidget中setMapNavigation定義如下:public function setMapNavigation(navMethod:String, status:String):void,其中參數:

navMethod:地圖導航的標記列表如下:(定義了Flex API類中的導航或者Sample Flex Viewer類的SiteContainer容器)

pan (Navigation.PAN) zoomin(Navigation.ZOOM_IN)

zoomout(Navigation.ZOOM_OUT)

zoomfull(SiteContainer.NAVIGATION_ZOOM_FULL)

zoomprevious(SiteContainer.NAVIGATION_ZOOM_PREVIOUS)

zoomnext     (SiteContainer.NAVIGATION_ZOOM_NEXT)

status: 在控制條的狀態欄顯示的文本文字

2.6 不使用WidgetTemplate模板開發Widget

開發widget並不一定會用到WidgetTemplate這個模板,再有的情況下,widget模板的窗口並不一定是必要的。比如,或許在你的應用程序中需要用一個與時鐘相關的widget來顯示當前的時間。這個時鐘並不需要一個window框架,其代碼如下:

<BaseWidget xmlns="com.esri.solutions.flexviewer.*"xmlns:mx="http://www.adobe.com/2006/mxml">

<mx:SWFLoader source="mywidgets/clock.swf"/>

 

</BaseWidget>

在上面的代碼中,我們使用一個SWFLoader來加載外部的flash文件到要開發 的widget中。然而,在這個時鐘微件中,會發現WidgetTemplate模板所提供的很多有用的特性我們根本沒用到。所以,作爲widget的開發員要有這樣一個共識,那就是隨時需要自己寫代碼來增加開發widget時所想到,而不是僅僅依賴既有模板所提供的那些特性。

2.7 開發一個自己的Widget模板

Widge編程模型允許開發者創建自己的widget模板。當然,新的widget模板類也需要實現iWidgetTemplate這個模板接口,因爲他是BaseWidget類與widget的模板之間進行交互的核心接口。實現一個接口就意味着裏面所有的方法都必須得以實現。這樣,新的widget模板類需要實現iWidgetTemplate接口中的setTitle,setIcon和setState這三個方法。下面說明如何創建一個基於Flex組件TitleWindow的widget模板MyTemplate:

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

<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" width="400" height="300"implements="com.esri.solutions.flexviewer.IWidgetTemplate">

<mx:Script>

<![CDATA[

public function setTitle(value:String):void

{

this.title = value;

}

public function setIcon(value:String):void{

}

public function setState(value:String):void{

}

]]>

</mx:Script>

</mx:TitleWindow>

接下來向MyTemplate組件中添加一些代碼,上面展示的只是一個最簡單的widget模板,它能夠接收widget的標題,圖標並在TitleWindow組件中進行配置。下一步我們在mywidgets空間(文件夾)下創建一個新的widget並,命名爲MyTempWidget,使用我們自己的模板,然後在其中添加一個按鈕。

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

<BaseWidget xmlns="com.esri.solutions.flexviewer.*"xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:mywidgets="mywidgets.*">

<mywidgets:MyTemplate>

<mx:Button label="Hello, World!"/>

</mywidgets:MyTemplate>

</BaseWidget>

2.8 修改或創建一個主題

Sample Flex Viewer應用程序的整體觀感都能夠自定義或是根據需要進行修改。這個主題(或者叫做‘皮膚’)它跟我們編程代碼是分開的。內置的主題名字叫做DarkAngle。DarkAngle皮膚是使用web上標準的層疊樣式列表文件com/esri/solutions/flexviewer/themes/darkangel/style.css進行構建的。這個CSS文件也能被編譯成一個獨立的主題文件,一個SWF。它在運行時被從配置文件config.xml所指定的位置加載到應用程序中。在config.xml配置文件中stylesheet標籤用來提供主題的swf文件的URL地址共應用程序訪問。注意: 對Sample Flex Viewer應用程序作的修改會在運行時自動的應用到各個微件。下面的步驟說明如何新建一個自己的主題:

第一步:修改DarkAngle的css文件或者新建一個css文件;新建css文件的話要遵循css標準,可以參考Flex開發文檔。

第二步 :改變或者是替換原有圖標:在css文件中有一些使用到內置圖標的圖像文件元素,你可以修改這些css文件中對於的圖標。

第三步:編譯css文件到swf文件中;這一步很重要只有編譯到swf文件才能被Sample Flex Viewer應用在運行時所識別和加載。要編譯這個css文件,只需要右鍵之並從彈出菜單選擇Compile CSS to SWF命令。選擇了這個命令以後,下次build這個Flex Viewer項目時css文件會被自動編譯到一個獨立的swf文件中去。爲了能夠重新生成主題文件,你可以再編譯一下當前的項目。

第四步:添加新建主題文件的URL到config.xml配置文件。要使用新建的主題文件,只需要修改config.xml中的stylesheet標籤,指定到編譯好的swf主題文件位置。

2.9 Widget配置

通過設計每個widget能夠產生自己的配置文件,這些配置文件的位置在Sample Flex Viewer裏config.xml相應的widget標記對中指定。widge編程模型只支持xml格式的配置文件。WidgetManager會把widget配置文件的URL傳給BaseWidget。BaseWidget會加載並分析這個xml格式的配置文件,然後在該文件的actionScript代碼段中設置一個public的屬性configXML傳遞配置參數。當widget創建完成後可以在自己的widget代碼中訪問到configXML這個屬性。即使盒外開發的Viewer只支持xml格式的配置文件,你也可用自己的配置文件來格式化widget代碼。這些配置文件會被Flex的HTTPservice服務連接並加載。在加載和分析其他格式的配置數據時也能使用相同的方法。

3 瞭解Sample Flex Viewer核心代碼

Sample Flex Viewer源代碼對公衆免費開放,而且在自定義和擴展Viewer的核心功能方面沒有任何限制。具體限制參考發佈包中許可文件。Flex Viewer的設計是爲了使開發者在擴展時更方便。通過Container Event Bus以及利用依賴注入這兩種設計方法可以實現高內聚和低耦合。在自定義Sample Flex Viewer的內核時,這兩張方法很重要。

3.1 事件總線容器

Event Bus容器是一個全局的時間發佈器,它是用來促進不同組件直接的交互(或者說信息傳遞)。事件總線容器在EventBus這個類(存在於EventBus.as文件)中定義,在SiteContainer類(存在於SiteContainer.mxml文件)中定義的一組靜態代理方法保證了能夠順利訪問event bus容器。下表說明了Configmanager如何加載配置並通過事件容器將其應用到其他組件的。當Configmanager被初始化以後,它就開始監聽事件,如圖:

public function ConfigManager()

{

super();

//make sure the container is properly initialized and then

//proceed with configuration initialization.

 

SiteContainer.addEventListener(SiteContainer.CONTAINER_INITIALIZED, init);

}

在上面的代碼中,定義的inti()函數是一個接收到事件後會開始加載配置數據的事件處理器。其中addEventListener方法又是一個用來訪問事件總線的代理方法。

圖5  Flex Viewer中Container組件的架構

當事件總線容器加載完畢以後SiteContainer容器就會發布CONTAINER_INITIALIZED 事件,具體參照以下代碼:

public function init():void

{

_container = this;

_lock = true//make sure only one container is created.

initLogging();//make sure the event bus is ready.

_containerEventDispatcher = EventBus.getInstance();

//tell the modules it's on business.

SiteContainer.dispatch(SiteContainer.CONTAINER_INITIALIZED);

}

在SiteContainer類中,如上所示,一旦被初始化,就會發布CONTAINER_INITIALIZED事件。通過使用發佈信息方法,組件之間可以在無需其他方法和數據的直接干預下進行監護。最終這些組件就通過這些基於事件的消息達到了去耦和分離的效果。這樣的話,只要組件之間的消息能夠同步,那麼任何組件的修改都不會直接影響到其他組件。

public function init(event:Event):void

{

   configLoad();

}

//config load

private function configLoad():void

{

   var configService:HTTPService = new HTTPService();

   configService.url = "config.xml";

   configService.resultFormat = "e4x";

   configService.addEventListener(ResultEvent.RESULT, configResult);

   configService.addEventListener(FaultEvent.FAULT, configFault);

   configService.send();

}

//config result

private function configResult(event:ResultEvent):void

{

   try

   {  

    //parse config.xml to create config data object

      var configData:ConfigData = new ConfigData();

      …………

      //dispatch event

   SiteContainer.dispatchEvent(new                    AppEvent(AppEvent.CONFIG_LOADED, false, false, configData));

}

在上面的表格中,一旦ConfigManager完成了對配置文件的分析,它就會發佈一個帶有配置信息的數據,而所有需要配置信息數據的組件,比如WidgetManager以及MapManager,只需要簡單的接收這個事件發佈的數據。

private function init():void

{

 

SiteContainer.addEventListener(AppEvent.CONFIG_LOADED, config);

}

這個通過事件總線發佈消息的方法可以在Sample Flex Viewer的核心代碼中找到。你也可以用相同的方法來添加組件或是改變組件之間交互的方式。

3.2 依賴注入(DI)

依賴注入在通常的電腦編程中指的是向一個軟件中的組件添加一個外部依賴的過程。應用控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體,將其所依賴的對象的引用,傳遞給它。也可以說,依賴被注入到對象中。所以,控制反轉是,關於一個對象如何獲取他所依賴的對象的引用,這個責任的反轉。

一般情況下,如果一個對象獲取了某一個服務資源,這個對象就有責任掛載這個服務:要麼是直接掛載這個服務所在位置的一個依賴關係,要麼轉到所謂的“服務查詢器”並請求它傳回一個特定類型服務實現的依賴。相反,如果使用依賴注入,這個對象只需要簡單的提供一個能夠掛載住該特定類型服務依賴的屬性即可;當這個對象被創建時,外部機制就會自動生成一個實現了該類型服務的依賴的屬性。這種依賴注入的方式提供了更好的靈活性,因爲使得創建給定服務類型的實現並將其應用於配置文件而不需要改變使用該類型服務的對象這個過程變得更加簡單。在Sample Flex Viewer中,這個過程體現在創建widget中,DI同樣能夠被用來創建自定義的widget模板。

下面的代碼介紹了WidgetManager是如何運用依賴注入在不需要知道widget的具體實現的情況下加載相應widget到容器的:

private function widgetReadyHandler(event:ModuleEvent):void

{

var info:IModuleInfo = event.module;

moduleTable.add(info.url, info);

var id:Number = info.data.id;

var label:String = configData.configWidgets[id].label;

var icon:String = configData.configWidgets[id].icon;

var config:String = configData.configWidgets[id].config;

var widget:IBaseWidget = info.factory.create() as IBaseWidget;

widget.setId(id); widget.setTitle(label); widget.setIcon(icon); widget.setConfig(config); widget.setConfigData(configData); widget.setMap(map); widgetTable.add(id, widget);

var widgetDO:DisplayObject = widget as DisplayObject;

addChild(widgetDO);

this.cursorManager.removeBusyCursor();

}

在上面代碼中,一旦widget模塊被加載,他就會轉變成IbaseWidget接口類型。而BaseWidget在這個Di應用中是需要擴展IbaseWidget接口的,這樣WidgetManager就不需要知道所操作的widget是那種類型或是具有哪些功能。WidgetManager只需要調用IbaseWidget中定義的各個方法來和已加載的widget進行交互。由此,實現widget的時候就不用關心它可能會有多麼的複雜,而且這個實現的過程跟WidgetManager乃至整個Flex Viewer容器是完全分離開的。在這種情況下,開發員就能夠相對自由地開發自己的widget而不受Flex Viewer框架的限制了。建議在開發自定義的Sample Flex Viewer核心功能時最好通過使用DI來保持這種開發widget的靈活性。這樣做可以通過添加微件而不是修改核心功能的特性來增加功能的一致性。這種方法可以使得你開發的程序比別人簡單許多,而且一定程度上避免了在添加功能特性操作的複雜性。

3.3 國際化

國際化(aka i18n)和本地化(aka l10n)有很多不同之處。國際化(internationalization)是設計和製造容易適應不同區域要求的產品的一種方式。它要求從產品中抽離所有的與語言,國家/地區和文化相關的元素。換言之,應用程序的功能和代碼設計考慮在不同地區運行的需要,其代碼簡化了不同本地版本的生產。開發這樣的程序的過程,就稱爲國際化。國際化根據用戶的需求不同,通常支持多種語言的選擇;而本地化通常是針對區域語言。由於跟國際化所依賴的語言元素不同,它們的設計方法也有所區別。

鑑於Sample Flex Viewer並不是最終設計和開發的成品,它以在代碼中以示例的形式支持國際化和本地化,而並沒有將其統一化。

3.3.1 使用Flex的國際化特性

對於Flex如何支撐國際化的具體細節,請參考Flex軟件開發工具包(SDK)文檔。在Sample Flex Viewer項目中創建了一個子文件夾nls來承載國際化的所有文本字符。比如,這裏提供了有兩種語言en_US(美式英語)和fr_FR(法語)。下面介紹配置Flex Builder使其支持國際化的步驟:

第一步:從項目屬性中添加編譯器選項;

第二步:把國際化的目錄路徑添加到Build Source;路徑中的{locale}允許編譯器根據步驟一中的編譯選項進行操作。

第三步:爲語言創建資源文件;比如說,我們在nls文件夾下的en_US以及fr_FR子文件夾中創建了一個資源文件WidgetTemplateStrings.properties然後Flex的編譯器能夠自動識別到擴展名properties。資源文件中的語言文本字符定義很簡單;

第四步:在代碼中使用國際化。比如在WidgetTemplate.mxml中使用國際化資源,需要先定義綁定到指定資源文件的資源綁定。

<mx:Metadata>[ResourceBundle("WidgetTemplateStrings")]

</mx:Metadata>

然後創建一個nlsString方法來檢索指定語言的字符串。

private function nlsString(nlsToken:String):String

{

return resourceManager.getString('WidgetFrameStrings', nlsToken);

}

addTitlebarButton("com/esri/solutions/flexviewer/assets/images/

widget/w_delete.png",nlsString("close"), closeWidget);

addTitlebarButton("com/esri/solutions/flexviewer/assets/images/

widget/w_min.png", nlsString("minimize"), minimizeWidget);

3.3.2 本地化設置

作爲一個可選方法,使用配置文件來使得標籤字符本地化還是很簡便的。Sample Flex Viewer中內置的widget 比如LiveMapsWidget就是個很好的例子。在這個widget種,標籤字符都被定義在widget的配置文件LiveMapsWidget.xml中。在這種情況下,如果想覆蓋默認語言設置的話,只需要編輯配置文件中的代碼即可。

<configuration>

<labels>

<visibilitylabel>Layer Visibility</visibilitylabel>

<transparencylabel>Layer Transparency</transparencylabel>

</labels>

</configuration>

3.4 日誌和錯誤處理

日誌和錯誤處理功能的結合有助於開發功能文檔和高質量的軟件。

日誌處理

在ActionScript和Flex的應用程序的日誌記錄中常常有很多可用的選項和工具。比如,我們在SiteContainer中設置了一個日誌文件來記錄遠過程調用協議(RPC)和基於基於網絡信息傳輸過程中的錯誤信息。HTTP連接是一類RPC連接,它記錄日誌文件的代碼如下:

private function initLogging():void {

// Create a target.

var logTarget:TraceTarget = new TraceTarget();

// Log only messages for the classes in the mx.rpc.* and

// mx.messaging packages.

logTarget.filters=["mx.rpc.*","mx.messaging.*"];

// Log on fatal levels.

logTarget.level = LogEventLevel.FATAL;

// Add date, time, category, and log level to the output.

logTarget.includeDate       =true;

logTarget.includeTime       =true; logTarget.includeCatego =true; logTarget.includeLevel  =true;// Begin logging.

Log.addTarget(logTarget);

}

這裏用的是基於Flex的日誌結構。更多詳細信息可用參考Flex文檔。

錯誤處理

ActionScript3提供了強大的堪比Java的錯誤處理機制。然而,相應的編譯器卻不能夠如後者一樣去預測潛在的錯誤和異常。所以,Flex或者說ActionScript的程序員就要自己使用錯誤事件處理器和try-catch異常捕獲功能來捕獲和處理編程過程中遇到的各種問題。最好的建議是:實現所有可能想到的錯誤事件; 儘量嘗試使用try-catch異常捕獲功能。

一旦發現錯誤,最好用直白易懂的語言去做標註並解釋錯誤情況。Sample Flex Viewer提供了一個簡單的錯誤顯示功能並能夠方便地發送和提示相應的錯誤信息。對於一個widget ,定義在BaseWidget中的一個public方法showError()能夠用來實現這一功能,例如:

showError("This is a <b>test</b> error message!");

這段代碼用來返回Sample Flex Viewer應用程序中出現的錯誤。注意到這段錯誤信息窗口只是一個形式,裏面的文本可以使用基本的Html標記進行必要的設計。在後臺,這個錯誤信息是通過前面一章講到過對的事件總線來進行傳遞的。換言之,錯誤信息能夠在Flex Viewer或者一個widget中根據需要任意傳播。

SiteContainer.dispatchEvent(new AppEvent(AppEvent.APP_ERROR,

false,

false,

“the error message string”));

4 Sample Flex Viewer框架和Widget部署

4.1 部署一個Sample Flex Viewer應用程序

如果你已經下載了Sample Flex Viewer的發佈包,那麼只需要簡單的解壓該zip文件到一個能夠訪問到網絡服務器的文件系統下面即可完成部署。也可能需要配置一下網絡服務器是的加載這個文件系統時輸入的URL更簡潔。比如在第2.3節中講到過,可以創建一個IIS的虛擬目錄,這一塊的部署跟其他Html的網絡應用程序部署方法基本相同。

部署自己編譯的Sample Flex Viewer 應用

如果你想使用自己編譯的代碼來部署Sample Flex Viewer應用程序,建議多做一步,就是用到Project菜單下的Export Release Build命令。因爲去除了相應的debug信息,到處的swf文件往往會更小。最終,這個應用比Debug後創建的程序更好用。默認情況下,Flex會創建一個新的文件夾bin-release來放置相關的發佈文件。而這個文件夾裏面的所有文件都可以是你的發佈包中的內容。也就意味着你可以對它重新命名,把它打包並部署到特定的網絡應用中去。

4.2 部署一個widget到Sample Flex Viewer

假設一個Sample Flex Viewer的應用已經部署並且也已開發好了一個widget,那麼下面說明如何配置這個widget:

第一步:把widget的swf文件複製到特定的文件位置;一個widge是一個獨立於外部的swf文件,你可以把該swf文件拷到Sample Flex Viewer應用的網絡服務器能夠訪問到的位置或者直接拷到另外一個網絡服務器上。

第二步:修改 Sample Flex Viewer應用的配置文件;配置文件config.xml在該應用程序的根文件夾下,該文件內部的widgets標籤下需要添加一個新的widget入口。Sample Flex Viewer應用程序支持widget在運行時配置到相同的網絡服務器時的相對路徑。這個新添加的widget標籤如下:

<widget label="A New Widget" icon="urlpath/myicon.png"menu="menuWidgets" config=”youconfig.xml”>relative/urlpath/MyNewWidget.swf</widget>

如果你將widget配置到了另外一個網絡服務器,那麼增加的widget表情裏面的Url應該是一個完整路徑。比如,應用到Icon圖像如下:

<widget label="A New Widget" icon="http://another-host/urlpath/myicon.png"menu="menuWidgets"config=”yourconfig.xml”>http://another-

host/urlpath/MyNewWidget.swf</widget>

你可以在widget中明確指定一個配置文件。在這個代碼中,定義於BaseWidget的的全局屬性configXML也能夠在widget中用到。目前,盒外開發的Sample Flex Viewer的應用程序只支持XML格式的配置文件並且能夠自動地構建configXML屬性。如果你想在自己的widget代碼中分析配置數據的話該配置文件可以使用任意格式。

第三步:刷新Sample Flex Viewer應用。當下次Sample Flex Viewer應用程序被刷新時,新建的widget的配置將會被自動識別並且這個widget能夠在用戶界面中通過tool菜單(或者在config.xml文件中自定義的菜單)調用。

4.3 安全性考慮

4.3.1 crossdomain.xml

一個雖法律上站不住但事實上卻普遍認知的網絡瀏覽器標準就是把安全沙盒強加到瀏覽器的插件中。這就意味着當前網頁運行的插件只能夠訪問通過相同網絡服務器提供的遠程資源。而Flash這個運行基於Flash開發的軟件的瀏覽器插件也會受到同樣的基於Flash開發的應用的沙盒限制。然而默認情況下,一個Flash應用只有在其他網絡服務器部署有一個crossdomain.xml文件的情況下才能從該服務器URL的根目錄下通過相關的Flash應用訪問遠程資源。

最簡單形式的crossdomain.xml文件如下:

<cross-domain-policy xsi:noNamespaceSchemaLocation="http://www.adobe.com/xml/schemas/PolicyFile.xsd">

<allow-access-from domain="*"/>

 

</cross-domain-policy>

這個crossdomain.xml文件能夠訪問由任何網絡上的服務器提供服務的Flash應用程序。可以參考Adobe Flex的文檔來了解設置這個文件的更多內容。注意:不管任何時候,只要運行Sample Flex viewer程序時發生了安全異常,就要及時檢查crossdomain.xml所部屬的資源服務器(比如ArcGIS的地圖服務),哪怕只是自己內部組織的錯誤。

4.3.2 網絡資源代理

在許多情況下,你需要訪問其他服務器所提供的資源,比如,各種GeoRSS在線反饋。如果這些反饋的服務器並沒有配置crossdomain.xml文件,那麼唯一的選擇就是在自己由Flash部署的服務器上設置一個網絡資源代理,並且在代碼中指定相關代理。

這個鏈接提供了一些有關代理的更多資料

http://resources.esri.com/help/9.3/arcgisserver/apis/javascript/arcgis/help/jshelp_start.htm#jshelp/ags_pro xy.htm

附錄: Configuration XML

關於config.xml配置文件的更多解釋請參閱源代碼中的readme.txt文件。

對於開發者,可以參考發佈包裏doc/ConfigXMLSchema目錄下的xml配置文件,這裏定義了config.xml文件中具體的XML標籤。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章