android之GoogleMap

Google Map

构建Android平台Google Map应用

Android 提供的地图(Map)功能可能是广大开发者非常关心的一个部分。到目前为止,开发内嵌式地图应用的软件是相当的困难,而且往往还需要支付很高的地图厂商的版权费用,加之手机上GPS功能的不完善,导致很多可以基于当前位置来开发功能的软件少之又少。就算是几个比较著名的LBS(Location-Based Service)软件,使用者也是寥寥。Android的出现打破这一格局,提供给普通开发者非常灵活的地图展示与控制功能。本文根据AndroidAPI 以及笔者亲身体验,给读者简单介绍下Android里面的MapView和MapActivity,通过简单的代码例子,期望给大家有所启示及探讨。

    MapView是个展示地图的视图。它可以获取键盘事件(onKeyDown 和onKeyUp) 来支持地图移动(东南西北)和缩放功能。它还支持多层Overlay,可以在地图上面画坐标,写地名,画图片等等。MapView只能通过MapActivity来建立。因为MapView需要在后台使用文件系统和网络,所有这些线程需要在Activity的生命周期中被控制。

Android 是通过布局(layout)来定义UI(用户界面)的。一般视图(View)可以直接在布局的xml 里面申明。但MapView不行,不知道是Google 故意的,还是当前API 没有实现。不过可以以自定义类来申明来实现:

1 class=”com.google.android.maps.MapView”
2   android:layout_width=”fill_parent”
3   android:layout_height=”fill_parent”
4   android:layout_weight=”1″ />

这样你可以添加你自己需要的其他视图,比如一个工具栏,或者一个EditText 来输入地址。

          基于MapView展示地图的视图

在详细进入coding 之前, 我们先介绍下经纬度(geocode)。

    经度是地球上一个地点离一根被称为本初子午线的南北方向走线以东或以西的度数。本初子午线的经度是0°,地球上其它地点的经度是向东到180°或向西到180°纬度是指某点与地球球心的连线和地球赤道面所成的线面角,其数值在0至90度之间。位于赤道以北的点的纬度叫北纬,记为N,位于赤道以南的点的纬度称南纬,记为S。基于纬度 phi (φ) 和经度 lambda (λ)的地图模型:

使用geocode,地球上任何一个地点都可以用精度+维度来代表。当然,geocode涉及的范围很广,本身就是一个很大的课题,以后有机会我们再讲。

    回到Android,com.google.android.maps.Point 这个类代表了一个地点的经纬度:Point(int latitudeE6, int longitudeE6),E6 是微度(microdegrees),就是度数再乘以1000000。目前如果要指定地图地点,一定要传递一个Point的类到地图中:

    // 纽约帝国大厦的经度和纬度

    Point p = new Point(40.748356*1000000,-73.984621*1000000);

    // 获取当前地图的控制器

    MapController mc = mapview.getController();

    // 地图中心移动到指定的点上

    mc.animateTo(p);

    // 放大到21级(level),level范围1-21

    mc.zoomTo(21);

 

你也可以使用zoomTo(int)来缩放到你需要的级别,比如获取当前缩放等级并再缩放一级(zoom out 1 morelevel):mc.zoomTo(mapview.getZoomLevel()-1)

mapview还提供了卫星图、路况图、街道图的功能:

获取街道图片:mapview.setStreetView(true)等。

大家可以清楚的看到,使用Android 的地图功能是非常的简单然后又很强大。那如何拿到一个地址的经度和纬度呢?有很多在线的服务可以使用。笔者比较喜欢Yahoo的Geo API :http://developer.yahoo.com/maps/rest/V1/geocode.html。Yahoo 的用户可以去免费申请一个appid,就可以使用所有Yahoo 提供的服务了。最简单的获取geocode的请求就是提供location的值:

    http://local.yahooapis.com/MapsService/V1/geocode?appid你的appid&location=350+5th+Ave,+New+York,+NY+10118

    在返回的XML中,我们只关心Latitude和Longitude的值:

    40.748396

    -73.984703

    在Android 中,可以通过包里面org.xml.sax 包来分析xml,也可以通过substring来做。如果你需要在地图上画地标、坐标、图片等等,那就需要定义你自己的Overlay 类:

    public class MyOverlay extends Overlay {

    // com.google.android.maps.Overlay

    然后override draw(Canvas canvas, PixelCalculatorcalculator, boolean shadow)这个方法。比如你想画个图标在当前的点上:

    super.draw(canvas, calculator, shadow)

    // 下面两行把当前的点转换成地图上的xy坐标

    int[] xyCoordinates = new int[2];

    calculator.getPointXY(p, xyCoordinates);

    // 在坐标这点画图(bitmap是Bitmap类,可以读取图片资源

    //(drawable resources)来生成)

    canvas.drawBitmap(bitmap, xyCoordinates[0],xyCoordinates[1], new Paint());

    // 在mapview中获得OverlayController:

    OverlayController oc = myMapView.createOverlayController();

    MyOverlay mo = new MyOverlay();

    // 加入到Overlay控制器就可以了

    oc.add(om, true);

    当然,你也可以在draw里面写字,画几何图形等等,这里就不一一叙述。

最后,我们看看如何获取键盘事件:

 1 public boolean onKeyDown(View v, int keyCode,KeyEvent event)
2    {
3    if (keyCode == KeyEvent.KEYCODE_I)
4    {
5
6    // 放大
7    mapview.getController().zoomTo(myMapView.getZoomLevel() + 1);
8    return true;
9    }
10    else if (keyCode == KeyEvent.KEYCODE_O)
11    {
12
13    // 缩小
14    mapview.getController().zoomTo(myMapView.getZoomLevel() – 1);
15    return true;
16    }
17    else if (keyCode == KeyEvent.KEYCODE_S)
18    {
19
20    // 转换到卫星地图
21    mapview.toggleSatellite();
22    return true;
23    }
24    else if (keyCode == KeyEvent.KEYCODE_T)
25    {
26
27 // 转换到路况图
28    mapview.toggleTraffic();
29    return true;
30    }
31    return false;
32    }

有兴趣的读者,可以去andoridcn 看看笔者发表的minigoogle map(包含所有source)。如果有机会,可以继续深入关于GPS的操作,如何在没有GPS硬件的情况下估计当前GPS位置,以及使用kml,nmea来模拟GPS路线等等。

    总结和技术展望

    Android本身设计和系统的实现是一个极其复杂的工作。就发稿时的m3-rc22a 版来看,系统还有需要充实的地方,相信在明年全面发布,真机发布之时,Android会变得更加强壮和易用。



posted @ 2011-10-29 23:20  程序学习笔记  阅读(509)  评论(0编辑  收藏  举报