一、概述
在上文《深入浅出Flex Viewer(二)——体系结构》中,笔者详细介绍了到Flex Viewer框架,使得读者能够对该框架源代码的关键目录和文件结构和这些文件中所包含或涉及到的系统的哪些构件;以及这些构件间的逻辑关系和连接这些构件所用的关键技术,如:消息总线(EventBus)、配置项管理(Config Manager)、数据共享机制(DataManager)等内容有一个大概地了解。在本文中将继续介绍Flex Viewer中框架配置技术的设计和实现原理,及其和框架其它组件间的关系。
二、框架配置技术是什么
框架配置是Flex Viewer中的一大特色,它能够通过一些简单的配置就能在无需修改框架源代码或重新编译的情况下对系统的参数进行修改,或对框架功能进行快速地扩展,从而可以保证框架始终都具备一个非常稳定的架构的同时还能够满足一定范围内需求的变化。
Flex Viewer中的框架配置技术主要体现在两个方面,即框架级配置和Widget级配置,其中Widget配置将在《深入浅出Flex Viewer (五)——Widget的原理》中介绍,而本文将集中介绍框架级配置。
Flex Viewer中的框架配置功能的核心是位于框架代码根目录下的congfig.xml文件,使用者可以使用规定的语法在该xml文件中对框架的初始化参数进行配置,例如,应用程序的标题、样式风格、地图、图层、Widget等。
<? xml version="1.0" ?>
<!--
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2010-2011 ESRI
//
// All rights reserved under the copyright laws of the United States.
// You may freely redistribute and use this software, with or
// without modification, provided you include the original copyright
// and use restrictions. See use restrictions in the file:
// <install location>/License.txt
//
// Read more about ArcGIS Viewer for Flex 2.3 - http://links.esri.com/flexviewer
//
////////////////////////////////////////////////////////////////////////////////
-->
< configuration >
< title > ArcGIS Viewer for Flex </ title >
< subtitle > a configurable web mapping application </ subtitle >
< logo > assets/images/logo.png </ logo >
< style >
< colors > 0xFFFFFF,0x333333,0x101010,0x000000,0xFFD700 </ colors >
< alpha > 0.8 </ alpha >
</ style >
<!-- replace the following url with your own geometryservice -->
< geometryservice url ="http://tasks.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer" />
<!-- replace the following key with your own Bing key -->
< bing key ="Ahw1due6dkmZg98wUJJYLrVmYlDik4oleCg6hoNqx6l2jFYRToImQH1HfH-asjjH" />
<!-- UI elements -->
< widget left ="10" top ="50" config ="widgets/Navigation/NavigationWidget.xml" url ="widgets/Navigation/NavigationWidget.swf" />
< widget right ="-2" bottom ="-2" config ="widgets/OverviewMap/OverviewMapWidget.xml" url ="widgets/OverviewMap/OverviewMapWidget.swf" />
< widget right ="20" top ="55" config ="widgets/MapSwitcher/MapSwitcherWidget.xml" url ="widgets/MapSwitcher/MapSwitcherWidget.swf" />
< widget left ="0" top ="0" config ="widgets/HeaderController/HeaderControllerWidget.xml" url ="widgets/HeaderController/HeaderControllerWidget.swf" />
< map wraparound180 ="true" initialextent ="-14083000 3139000 -10879000 5458000" fullextent ="-20000000 -20000000 20000000 20000000" top ="40" >
< basemaps >
< layer label ="Streets" type ="tiled" visible ="true"
url ="http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer" />
< layer label ="Aerial" type ="tiled" visible ="false"
url ="http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer" />
< layer label ="Topo" type ="tiled" visible ="false"
url ="http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer" />
</ basemaps >
< operationallayers >
< layer label ="Demographics" type ="tiled" visible ="false" alpha ="0.5"
url ="http://server.arcgisonline.com/ArcGIS/rest/services/Demographics/USA_Median_Household_Income/MapServer" >
< sublayer id ="1" popupconfig ="popups/PopUp_Demographics_BlockGroups.xml" />
< sublayer id ="2" popupconfig ="popups/PopUp_Demographics_Tracts.xml" />
< sublayer id ="3" popupconfig ="popups/PopUp_Demographics_Counties.xml" />
< sublayer id ="4" popupconfig ="popups/PopUp_Demographics_States.xml" />
</ layer >
< layer label ="Boundaries and Places" type ="tiled" visible ="false"
url ="http://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places_Alternate/MapServer" />
< layer label ="Fires" type ="feature" visible ="false" alpha ="1.0"
popupconfig ="popups/PopUp_Fires.xml"
url ="http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Fire/Sheep/FeatureServer/0" />
</ operationallayers >
</ map >
<!-- widgets organized into widget containers that manage close/open etc -->
<!-- supported layout property options: horizontal(default)|float|vertical|fix -->
< widgetcontainer layout ="float" >
< widget label ="Bookmarks" left ="430" top ="90"
icon ="assets/images/i_bookmark.png"
config ="widgets/Bookmark/BookmarkWidget.xml"
url ="widgets/Bookmark/BookmarkWidget.swf" />
< widget label ="Find an address" left ="100" top ="90" preload ="open"
icon ="assets/images/i_target.png"
config ="widgets/Locate/LocateWidget_Bing.xml"
url ="widgets/Locate/LocateWidget.swf" />
< widget label ="Louisville Police" left ="590" top ="280"
icon ="assets/images/i_police.png"
config ="widgets/Query/QueryWidget_Louisville_PoliceStations.xml"
url ="widgets/Query/QueryWidget.swf" />
< widget label ="Search" left ="80" top ="280"
icon ="assets/images/i_search.png"
config ="widgets/Search/SearchWidget_Louisville.xml"
url ="widgets/Search/SearchWidget.swf" />
< widget label ="Earthquakes (GeoRSS)" left ="410" top ="280"
icon ="assets/images/i_rss.png"
config ="widgets/GeoRSS/GeoRSSWidget.xml"
url ="widgets/GeoRSS/GeoRSSWidget.swf" />
< widget label ="Draw and Measure" left ="60" top ="400"
icon ="assets/images/i_draw2.png"
config ="widgets/Draw/DrawWidget.xml"
url ="widgets/Draw/DrawWidget.swf" />
< widget label ="Print" left ="390" top ="400"
icon ="assets/images/i_print.png"
config ="widgets/Print/PrintWidget.xml"
url ="widgets/Print/PrintWidget.swf" />
<!--
<widget label="My first widget"
icon="assets/images/i_widget.png"
config="widgets/Samples/HelloWorld/HelloWorldWidget.xml"
url="widgets/Samples/HelloWorld/HelloWorldWidget.swf"/>
-->
</ widgetcontainer >
</ configuration >
三、框架配置的实现原理
在框架中主要有六大组件,即ViewerContainer、ConfigManager、DataManager、MapManager、UIManager、WidgetManager(见《深入浅出Flex Viewer(二)——体系结构》)。在进行框架配置初始化的整个过程中,这些组件均有参与。从参与程度来看,ConfigManager是配置文件解析的核心类,ViewerContainer类的实例管理了其它组件实例,另外四个组件主要是使用ConfigManager中得到的configData(记录了xml文件中所有的相关参数)。那么,下面将深入剖析源代码来呈现配置文件初始化的整个过程。
在flex应用程序的入口文件index.mxml中,代码如下:
< viewer:ViewerContainer >
< viewer:configManager >
< managers:ConfigManager />
</ viewer:configManager >
< viewer:dataManager >
< managers:DataManager />
</ viewer:dataManager >
< viewer:mapManager >
< managers:MapManager />
</ viewer:mapManager >
< viewer:uiManager >
< managers:UIManager />
</ viewer:uiManager >
< viewer:widgetManager >
< managers:WidgetManager />
</ viewer:widgetManager >
</ viewer:ViewerContainer >
代码2.index.mxml
在以上代码中,ViewerContainer的实例管理了其它的组件,在各类实例的初始化时,其初始化的顺序如下(由于DataManager、MapManager、UIManager、WidgetManager等四类在框架配置过程中的地位相同,均是配置参数的使用方,所以在下表中仅列DataManager):
顺序号 |
ViewerContainer |
ConfigManager |
DataManager |
1 |
创建实例 xml配置文件地址的来源: A、直接硬编码 B、从url参数中解析出配置文件地址 |
||
2 |
创建实例 监听事件: ViewerContainer.CONTAINER_INITIALIZED |
||
3 |
创建实例: 监听: AppEvent.CONFIG_LOADED AppEvent.DATA_FETCH_ALL AppEvent.DATA_PUBLISH AppEvent.DATA_FETCH |
||
4 |
Init 监听: AppEvent.APP_ERROR AppEvent.CONFIG_LOADED |
||
5 |
事件发布: ViewerContainer.CONTAINER_INITIALIZED |
||
6 |
处理事件: ViewerContainer.CONTAINER_INITIALIZED Init: config:加载并解析ViewerContainer中设置的配置文件 ,最后填入configData变量 |
||
7 |
事件发布: AppEvent.CONFIG_LOADED (configData) |
||
8 |
接收并处理事件: AppEvent.CONFIG_LOADED |
当ConfigManager中发布事件AppEvent.CONFIG_LOADED的同时将从配置文件中解析出来的配置参数变量configData作为事件参数发布到消息总线上,然后凡是订阅了该消息的组件均会在其相应的事件处理函数中接收到configData变量,从而对其自身进行初始化。
这便是框架配置初始化的全部过程。
四、我们在哪
本文介绍了flex viewer中框架配置技术,并从源代码的角度深入剖析了其实现的原理。另外,本文在ConfigManager解析配置文件的具体过程由于比较简单,读者可以自己阅读,在此就不详细说明。
那么在本系列下一篇文章《深入浅出Flex Viewer (四)——系统初始化的那些事儿》中,笔者将继续从源代码的角度来深入剖析系统初始化的整个过程,让读者能够对整个应用程序框架的运行原理了然于心。
《深入浅出Flex Viewer (三)——Config文件详解》
《深入浅出Flex Viewer (四)——系统初始化的那些事儿》
《深入浅出Flex Viewer (五)——Widget的原理》
《深入浅出Flex Viewer (六)——如何增加新的数据源》
注:在本文发表时flex viewer的版本是2.3,2.3和2.1版本在架构上没有什么改变,故本文以2.3版本为依据来探讨。