2008年10月29日星期三

Android解析KML

KML服务有两种,一种是纯文本的XML,一种是将一个纯文本的XML文件和其他资源(如图标)进行zip压缩后形成的KMZ,本质是zip。使用Android解析KML服务需要根据情况首先判断是否需要解压缩,然后再解析XML文本。

Android Java中包含了zip压缩解压缩工具库,可以从“java.util.zip”包中进行调用。我们看一下一个KMZ如何被解压缩:

URL url = new URL(strUrl);
HttpURLConnection uc = (HttpURLConnection) url.openConnection();

InputStream isKxml = null;

ZipInputStream zipIs = new ZipInputStream(uc.getInputStream());
ZipEntry zipEntry = null;
while ((zipEntry = zipIs.getNextEntry()) != null)
{
String zipEntryName = zipEntry.getName();
if (zipEntryName.endsWith("kml"))
{
ByteArrayOutputStream os = new ByteArrayOutputStream();
byte[] b = new byte[512];
int readedByteSize = 0;
while ((readedByteSize = zipIs.read(b)) > 0)
{
os.write(b, 0, readedByteSize);
}
os.flush();
os.close();

isKxml = new ByteArrayInputStream(os.toByteArray());
}
else if (zipEntryName.endsWith("png"))
{
ByteArrayOutputStream os = new ByteArrayOutputStream();
byte[] b = new byte[512];
int readedByteSize = 0;
while ((readedByteSize = zipIs.read(b)) > 0)
{
os.write(b, 0, readedByteSize);
}
os.flush();
os.close();

InputStream isBitmap = new ByteArrayInputStream(os
.toByteArray());
Bitmap bitmap = BitmapFactory.decodeStream(isBitmap);
kml.addBitmap(zipEntryName, bitmap);
isBitmap.close();
}
}
zipIs.close();

Reader reader = new InputStreamReader(isKxml);
parseKxml(kml, reader);//解析KML文本的方法
isKxml.close();
reader.close();

好了,解压缩完成后,重点就在解析KML文本上了。鉴于移动终端的KML内容不应该很大,因此在这里使用了XmlDocument方法解析,下面看一下方法:

private static void parseKxml(Kml kml, Reader reader) throws Exception
{
KXmlParser kXmlParser = new KXmlParser();
kXmlParser.setInput(reader);
Document doc = new Document();
doc.parse(kXmlParser);

if (doc == null) return;

Element eRoot = doc.getRootElement();
……(处理XML Element)
}

2008年10月24日星期五

ArcGIS Flex Demo

截屏:

Demo地址:在新窗口打开
源代码地址:在新窗口打开

2008年10月16日星期四

ArcGIS API for Flex入门 - 7.API学习路线

如果我的这一系列文章不对你的胃口,或者你更喜欢官方一点的学习文档,我这里整理了一些在线资源和建议的学习路线,供你参考:)

首先,你是否了解Flex,如果你还不了解Flex和它的开发环境,那么可以到这里看看:
Flex 入门
Flex 语言参考

如果你对Flex已经有了一定了解,并准备开始使用ArcGIS API for Flex,那么首先推荐看一个ESRI的在线视频教你如何配置开发环境,工欲善其事必先利其器嘛。
《Creating an application using the ArcGIS API for Flex》

当你对Flex的MXML和ActionScript语言都有所了解,同时已经配置好ArcGIS API for Flex并且可以创建Flex应用以后,案例驱动是最好的学习方法,下面是ArcGIS API for Flex的在线Sample及其源代码。
ArcGIS API for Flex 在线Sample

在开发过程中,对ArcGIS API for Flex有任何疑问,最好的解决办法是查看API参考:
ArcGIS Flex API参考

最后,说点和ArcGIS API for Flex无关的话题,那就是Flex在WebGIS中的作用。使用Flex最大的好处是无需对原来的GIS系统和网站进行重新设计和架构,只需适时嵌入Flex应用即可达到非常好的效果。在这里,再附上一个Flex 3D Map的演示,看了这个演示你会对Flex如何促进WebGIS应用的表现能力有更为直观的了解:
http://thunderhead.esri.com/readonlyurl/HeatMap3D.html

上一节

【结束】

ArcGIS API for Flex入门 - 6.有多少Task可以重来

上一小节我们了解了Flex API中的Task用法,你可以把Task想象成一条命令,当你把命令发送到服务器的时候,服务器会执行并返回给你结果——当然,前提是要服务器提供这个服务。上一节的例子是IdentifyTask,其它的Task大抵也可以触类旁通。可是,API的Task包的命名因为不同Task的功能不同而并不很一致,有些Task的名称并不是以Task结尾,同时,并不是所有的Task都可以execute。所以,我们在这一小节重点讨论一下各种Task的作用和用法。

1.FindTask
这是一个很简洁的Task,它的功能主要是通过关键字来搜索要素的某些字段,如果符合则返回查找到的要素。你可以参考Sample的“FindTask.mxml”,下面是对Task定义的一些代码:
我们似乎已经可以摸到Task的一般套路,先生成一个参数对象,对这个Task需要完成的任务进行一些设定,然后将Task与这些参数联系起来,最后执行等待服务器返回处理结果。这个FindTask就是这样,简洁明了。

2.GeometryService
这是对几何对象进行处理的一个Task,可是它是以Service结尾,这代表它并不简单地给你execute一下的,它提供了处理多种任务的能力。比如缓冲(buffer)、量测(lengths)等等。让我们打开Sample的“BufferSample.mxml”看看,这是一个缓冲的例子。

我们可以看到,处理的过程和其它Task也没什么区别,只不过没有了execute(有你也不知道到底执行什么命令),取代它的是明确的任务名称,比如要进行缓冲,那就是用buffer方法:
myGeometryService.buffer( bufferParameters );

好,那么随之而来的一个问题就是执行完了怎么办,怎么区分不同命令返回的结果?事实上,你只要监听不同的时间好了,比如你执行buffer命令,那么你就监听BUFFER_COMPLETE事件(mxml中:bufferComplete="..."),好了,只要你的方法监听到这个事件,你就可以在buffer完成后进行后续的处理了。

3.Geoprocessor
这是GP服务对应的Task。GP服务很灵活,因此你在设置Geoprocessor任务参数(Object对象)的时候,需要给予更多的注意。在用法上它并没有很多新意,具体可以参考一下Sample的“GeoprocessorMessageInABottle.mxml”。

4.IdentifyTask
识别要素,老朋友了,具体参考上一节。

5.Locator
从地址获得要素或者从要素获得地址的Task。让我们打开Sample的“LocatorTask.mxml”看一下,下面是执行命令的代码:
locateTask.addressToLocations(addy, null, new AsyncResponder(onResult, onFault));

Locator主要提供两个命令:addressToLocations()和locationToAddress()。它的参数也是Object对象,因此提供了灵活的参数设置和更多出错的机会。

6.QueryTask
查询要素。FindTask是搜索某些字段文本的命令,而QueryTask则提供了文本查询和空间查询的能力。sample中的“QueryTaskOnMap.mxml”是一个文本查询的例子。让我们对它进行一些修改以进行空间查询:

执行查询的命令是queryTask.execute( query, new AsyncResponder( onResult, onFault ));
让我们在它之前加上:
query.geometry = map.extent;
query.spatialRelationship = Query.SPATIAL_REL_INTERSECTS;

上面的map是Map组件的id(自己添加),同时,把query原先定义的text属性删除。让我们运行以后再点击查询,拖动一下地图,是不是看到只有原先视口中的要素被高亮了出来?这就是空间查询的结果,因为上面执行的查询是以当前地图范围为过滤条件的。


上一节 下一节

2008年10月15日星期三

ArcGIS API for Flex入门 - 5.任务Task

Task是ArcGIS Server的重要组成部分,一个Task可以执行某些特定的任务,比如Identify、Query等等。在这个小节,我们通过IdentifyTask来认识Task的使用方法。

IdentifyTask是一个可以识别要素的任务,让我们打开Sample的“IdentifySample.mxml”,看一下其中核心的代码。

我们首先注意一下在Flex Application中添加了这样一个IdentifyTask的标签:

我们设想的功能大概是这样的:先在地图上画一个多边形,然后识别多边形内的所有要素,最后在图上标注出来。让我们看一下这个功能在Flex中是如何通过Task执行完成的:

首先是绘图,我首先需要在地图上画一个多边形,在ArcGIS API for Flex中有一个提供绘图的工具条com.esri.ags.toolbars.Draw,通过它我们可以很轻松地实现绘图功能:
如上所示,IdentifySample在Draw对象上添加一个事件监听器,当绘图完成时,执行drawEndHandler()方法,在这个方法中,我们将继续绘图以后的工作。

在已经绘制了一个多边形以后,我们就需要执行IdentifyTask来进行要素识别了。先看一下代码:
private function drawEndHandler(event:DrawEvent):void
{
var geometry : Geometry = event.geometry;

var identifyParams : IdentifyParameters = new IdentifyParameters();
identifyParams.returnGeometry = true;
identifyParams.tolerance = 3;
identifyParams.width = 600;
identifyParams.height = 550;
identifyParams.geometry = geometry;
switch (layerOption.value)
{
case "top":
identifyParams.layerOption = IdentifyParameters.LAYER_OPTION_TOP;
break;
case "visible":
identifyParams.layerOption = IdentifyParameters.LAYER_OPTION_VISIBLE;
break;
case "all":
identifyParams.layerOption = IdentifyParameters.LAYER_OPTION_ALL;
break;
}
identifyParams.mapExtent = map.extent;

identifyTask.execute( identifyParams );
}

在DrawEvent对象中,我们可以获取刚才绘图的Geometry对象,这个Geometry对象用于Identify的参数设置中,如果你做过ArcEngine开发,你可以对比一下SpatialFilter。好,再设置了一下需要搜索的图层和范围以后,你就可以执行这个IdentifyTask了,看到execute是不是很兴奋?

然后呢?我们回头看看这个IdentifyTask的定义,其中注册了当Task完成时候执行的方法:identifyCompleteHandler()。
private function identifyCompleteHandler(event:IdentifyEvent):void
{
for each (var result:IdentifyResult in event.identifyResults)
{
myGraphicsLayer.add(result.feature);
}
}
看明白了么?这个方法就是在GraphicLayer上把这个Task的结果画出来。

通过这个流程,你应该明白了Task的作用和用法了吧。

上一节 下一节

ArcGIS API for Flex入门 - 4.事件Event

前面讨论的主要是怎么样去操作Map,设定各种数据啊,通知它更新数据源啊等等。目前,你已经可以通过ArcGIS API for Flex渲染各种漂亮的地图了。下面,我们应当来想想怎么来做更多的事情了。

比如在你的Flex Application中,你希望在用户在点击Map的时候,获取到用户点击的坐标,然后到数据库去查找附近是不是有好吃的餐馆之类的。这个时候你应该想到我们应该要处理Map的事件了。

这里插播一句,ArcGIS API for Flex最重要的就是Map组件,你完全可以把Map组件等同于其他原生的Flex组件来使用。——所以,如果你很熟悉Flex,那么本小节下面的内容你可以跳过了。

好,我们打开Sample的“EventBasics.mxml”,在onApplicationCreationComplete()方法(它监听了Application的创建完成事件)中,其中添加了Map组件的鼠标click事件监听器:
myMap.addEventListener(MouseEvent.CLICK, logMouseEvent);
其中的logMouseEvent在下面进行了定义:
public function logMouseEvent(event:MouseEvent):void
{
log.text = "* MouseEvent: " + event.type + "\n" + log.text;
}

每当用户在Map上进行点击时,Map就会自动分发MouseEvent.CLICK事件,而监听Click事件的logMouseEvent()方法就会被执行。运行一个这个“EventBasics.mxml”,试着在地图上点击几下,有没有看到右面的文本变化?

当然,ArcGIS 的Map组件提供了许多的Event,涵盖地图操作、图层操作、查询操作、绘图操作等等,你可以在此基础上实现任何你想实现的功能。

上一节 下一节

ArcGIS API for Flex入门 - 3.数据的绑定

在这一小节里,我们主要讨论数据绑定的问题。事实上这是属于Flex的范畴,如果你对Flex语言很熟悉,那你完全可以跳过这一节。

在前面的小节,我们已经学会了如何在Flex Application中加入一个Map组件,并且在Map组件中添加了一个ArcGISTiledMapServiceLayer图层,当然,ArcGIS Flex不仅支持切片图层,还有ArcGISDynamicMapServiceLayer、ArcGISMapServiceLayer、ArcGISImageServiceLayer、ArcIMSMapServiceLayer,这些类型的图层都可以顾名思义,熟悉ArcGIS Server的你肯定不陌生。

这时,如果你想要实现这样的功能:点击一个按钮(或者选中下拉框的一个选项),当前的Map中的地图就自动地切换——就像Google Map一样,你可以选择卫星图或者切片地图。当然,你可以这样做:在每个按钮的Click事件中,获得需要更新的图层URL,然后通知Map:换图层了!没有任何问题,但是,在Flex有更加“面对对象”的方法:数据绑定。

我是一个很懒的人,所以我经常引用的代码就是ArcGIS API for Flex自带的Sample(后面我说的Sample就是Flex API的例子,我就不重复说明了,这样的简称应该没有诸如RTFM之类的难懂吧)。这次也不例外,让我们打开Sample中的agol.mxml。
我们注意,在Map元素的属性中,有一个url定义,当然这就是地图服务的地址。然而这个地址并不是一个通常的字符串,在其中嵌入了一段“{servicePicker.selectedItem.toString()}”。这个servicePicker是什么呢,往下看几行,我们可以看到,在这个Flex Application中的ComboBox的id是servicePicker,这个ComboBox就是供你来选择地图服务的。顺便提一下,Flex背后站着的其实是Flash,因此id在Flex中有着非常重要的作用。

好,我们看看这段代码到底是什么意思。Flex组件默认监听了名为propertyChange的事件,当自身的数据改变的时候,它就会分发这一事件,这时,使用花括号括起来的对象就会接受到对应的事件并更新自身的数据。“{servicePicker}”监听的是id为servicePicker的下拉框的组件,当我们在下拉框选择了某个地图服务的时候,“{servicePicker.selectedItem.toString()}”就会根据这个下拉框的选择项生成一个字符串,再把字符串拼接到Map的url属性中去。Map就会根据新的url获取数据并进行渲染。这就是一种“面对对象”的数据处理方式。

上一节 下一节

2008年10月13日星期一

ArcGIS API for Flex入门 - 2.配置开发环境和HelloWorld

如何配置Flex开发环境,参考前作:《ArcGIS API for Flex 配置使用》

在这篇叙述如何进行开发环境配置的文档中,最后测试环境时使用了Flex API的一个Sample。我们来看一下那个Sample的具体内容(“Tutorial_Map.mxml”)。


在“mx:application”元素(顾名思义,这就定义了一个Flex应用)中首先定义了mx和esri,它们分别是Flex和ArcGIS的命名空间,通过命名空间就可以引用到相应的内容,比如“esri:Map”对应的就是API中的com.esri.ags.Map这个类。

事实上,mxml文件会首先被编译成ActionScript,通过mxml定义和通过ActionScript定义在效果上是等效的。比如在mxml中添加标签:
esri:Map
等同于as脚本:
import com.esri.ags.Map;
var map:Map= new Map();


继续来看这个Sample,在定义了Map以后,又往其中添加了2个元素:extent和ArcGISTiledMapServiceLayer。也就是在新建了一个Map以后,设定了当前的可视范围,然后再添加了一个切片图层。做完这几步简单的工作以后,Map就可以渲染出一幅漂亮的地图了。我们可以看到,使用ArcGIS API for Flex来开发是一件非常简单的事情。

好,下面我们试着用ActionScript来替换xml标签来做相同的事情:

运行它,你可以看到,效果和原来的Sample是完全一样的。

上一节 下一节

ArcGIS API for Flex入门 - 1.概述

【环境】ArcGIS Server 9.3,ArcGIS API for Flex 1.0 beta,Adobe Flex Builder 3

ArcGIS最新推出了Flex API,主要面向基于ArcGIS Server 的RIA开发。RIA近来越来越火热,Flex/Flash在RIA领域又是绝对的翘楚,ArcGIS在这个时候推出Flex API实在是太理所当然了。

如果你还不太了解Flex,那么你可能会知道Adobe公司的Flash。作为现在主要浏览器均支持的一个必备插件,Flash占据了Web浏览98%的市场份额。Flash可以整合图片、音频、视频、矢量图画、动画等各种资源,并提供良好的交互,因此在浏览器上可以提供给用户非常良好的体验。这就是Flash流行的原因。

Flex则是Adobe最近推出的SDK,旨在帮助程序员进行Flash开发。要知道,Flash里面的影片剪辑、时间线等等概念都是为动画美工所熟知的,但是和程序员的思维实在是大相径庭。因此,Adobe推出了这个可以使用xml、ActionScript(在Flash中同样存在)进行编程的工具——Flex。当然,Flex可以做的事情,Flash都可以做。Flex就像是一个作坊,在作坊里工作你就可以顺利生产出Flash(*.swf)来——况且,这个工作并不复杂。

在Flex和Flash中主要的开发语言是ActionScript(以下简称as),这是一种语法结构和JavaScript很像的脚本语言,也是对Flash进行控制的根本方法。其实,Flex只需要as就可以工作了,其提供的mxml(xml)只不过为了方便开发人员进行布局和快速开发的一个工具。mxml文件最终都会编译成as脚本,并在Flash中执行。

ArcGIS API for Flex(以下简称Flex API)能帮助你做什么呢?事实上这个API是以Flex组件库的形式存在的。当你在你的Flex项目中添加了Flex API,你可以像开发桌面程序一样拖动一个Flex控件到你的应用中,做些简单的设置就可以进行GIS操作:浏览、查询……你可以想象一下你正在使用ArcEngine进行开发……

我以前有写Flex API概述《ArcGIS API for Flex概览》,这里就不再赘述了。

下一节

2008年10月12日星期日

Open API

其实大家都希望开放自己的API以后,吸引开发人员在自己的平台上做点事情。吹得美妙无比,内心都险恶得要死巴不得天底下别的API都死绝了,大家都用我的吧。Open API是一个比云更ws的概念,它的口号就是:我的是我的,你的还是我的。小子,我这里有全套工具,来给我打工吧!好,你就瞎忙活去吧。

你要用它的API在它那里实现了什么功能,恭喜你,你已经正式成为了它的免费兼职实习生;你要用它的API在你自己那里使用了什么功能,给它打了广告不说,啥时候你的流量大了,对不起,从今天开始限制访问量,非付费用户每天限制IP500个,不够?交钱啊。这叫什么,消费陷阱啊。

所以啊,云啊雾啊开放啥的都是虚的,数据才是根本。有了数据你才有发言权,你才有资本去做云啊雾的,然后对大家招招手说:hey come on,给你露几个接口,用去吧。ok,到时候你也会说:Open API好,云实在是好。