简介: 随着移动互联网应用的迅速发展,利用智能手机提供的实时地理位置信息服务功能扩展出众多 LBS(Location Based Service) 应用,将实时地理位置信息与手机的便捷、移动特性结合,为人们提供多种多样的应用场景,比如实时定位、导航、搜索周围好友、基于地理位置的信息推荐等。本文通过实例介绍如何开发基于 Google Map 的 Android 应用。
概述
本文以实例介绍如何开发基于 Google Map 的 Android 应用,共分为五部分:1. 开发 Android 应用的准备以及 Google Map API 密钥的获取;2. 将 google 地图控件放入 Android 工程中;3. 添加地图缩放组件,以及地图模式,缩放比例的调整;4. 使用 Android 系统提供的地理位置信息的服务获取当前地理位置信息;5. 将当前地理位置信息以图标的方式显示在地图上。
开发 android 应用的准备
本文将主要介绍如何在 Android 系统上开发基于 Google 地图的应用。在开始阅读这篇文章之前,需要具备基本的 Android 开发的相关知识。读者需要了解如何在 eclipse 开发简单的 android 应用程序,例如 Eclipse IDE 的配置和 Android SDK 的安装。
● Eclipse IDE(http://www.eclipse.org/downloads/)
● AndroidSDK(http://developer.android.com/sdk/index.html)
为了开发基于 Google map 的 Android 应用,同时还需要安装 Google APIs Add-on,以及创建包含有 Google API 的 Android 模拟器。
● Google APIs Add-on(http://code.google.com/android/add-ons/google-apis/installing.html)
● AndroidVirtual device Targeting Google APIs(http://developer.android.com/guide/developing/devices/index.html)
获取 Google 地图 API key,以及生成 keyStore 文件
使用 google map 第一步是要获得 google map API 密钥,一个密钥只对一个”目录”或者”域”有效,对于 Google 来说,获取密钥的过程其实也是认证的过程,在你获取密钥时,需要同意 Google 所列出的一些法律条款,所以在你使用获取密钥后,Google 默认你已经同意了其地图使用的条款。
获取密钥的过程可以简单分为两个阶段:
阶段 1:获得 MD5 指纹并创建证书
通过 JDK( 本文中所指的 JDK 均为 Oracle JDK) 中自带的 Keytool.exe 工具来生成证书,Keytool.exe 可以在 %JAVA_HOME%\jdk1.6.0_21\bin 里找到,
图 1. 创建证书
为了开发和调试基于 Google Map 的 Android 应用,我们可以使用在 Android 应用调试模式下的证书 debug.keystore,该文件一般存放在 : %userprofile%/.android/
在笔者的 Windows XP 系统中,该文件的存放路径为
C:\Documents and Settings\Administrator\.android\
将 debug.keystore 文件复制到 Keytool 工具的目录下,然后通过下面的命令来获取证书的 MD5 值 : keytool.exe -list -alias androiddebugkey -keystore debug.keystore -storepass android -keypass android
图 2. 获取证书的 MD5 值
阶段 2:获取 Google Map 的 API 密钥
登陆 http://code.google.com/android/maps-api-signup.html,通过使用之前获得的 MD5 值,来完成 Google Map API 密钥的申请。图 3 为申请成功的截图。
图 3. 申请 Google Map API 密钥界面
创建一个 Android 工程
1.建立新的 Android 工程,并命名为 GoogleMapExample,开发基于 Google Map 的应用需要指定该工程的 build target 为 Google APIs。
图 4. 创建 Android 工程界
2.开发 Android 应用可以在手机或者模拟器上进行调试,如果使用模拟器进行开发,首先需要创建 Android 模拟器,并且指定该模拟器的 target 为 Google APIs。
图 5. 创建 Android 模拟器界面
3.设置示例工程的运行环境,确保示例工程运行在包含有 Google API 的目标模拟器上。
图 6. 设置示例工程运行环境界面
4.在模拟器上运行 GoogleMapExample 示例工程,模拟器应该有如图 7 的输出。自此,开发基于 Google Map 应用的工程就初步搭建起来了,接下来我们一步一步来将地图控件添加进 GoogleMapExample 应用中
图 7. 运行结果界面
将 Google Map 控件添加到 GoogleMapExample 工程中
首先,在 AndroidManifest.xml 文件中添加对于 Google Map 库的引用。通过使用 uses-library 标签来添加 google map 库到当前应用中。
清单 1. 添加对于 Google Map 库的引用
1 | < uses-library android:name = "com.google.android.maps" /> |
添加的相应的访问权限:
● android.permission.ACCESS_COARSE_LOCATION: 允许应用通过网络信息获取当前地理位置信息的权限。
● android.permission.ACCESS_FINE_LOCATION: 允许应用通过 GPS 获取当前地理位置信息的权限,较网络获得的地理位置信息更为精确。
● android.permission.INTERNET: 允许应用访问网络的权限。
最终的 AndroidManifest.xml 文件示例如下:
清单 2. AndroidManifest.xml 文件
1 | <? xml version = "1.0" encoding = "utf-8" ?> < manifest xmlns:android = "http://schemas.android.com/apk/res/android" package = "com.android.mapExample" android:versionCode = "1" android:versionName = "1.0" > < uses-sdk android:minSdkVersion = "3" /> < uses-permission android:name = "android.permission.ACCESS_FINE_LOCATION" /> < uses-permission android:name = "android.permission.INTERNET" /> < uses-permission android:name = "android.permission.ACCESS_COARSE_LOCATION" /> < application android:icon = "@drawable/icon" android:label = "@string/app_name" > < uses-library android:name = "com.google.android.maps" /> < activity android:name = ".GoogleMapExampleActivity" android:label = "@string/app_name" > < intent-filter > < action android:name = "android.intent.action.MAIN" /> < category android:name = "android.intent.category.LAUNCHER" /> </ intent-filter > </ activity > </ application > </ manifest > |
其次,将 MapView 控件添加进布局文件 main.xml 中,并将 1.3 中获得的 API 填入 MapView 控件的声明中。
清单 3. main.xml 文件、
1 | <? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" android:orientation = "vertical" android:layout_width = "fill_parent" android:layout_height = "fill_parent" > < com.google.android.maps.MapView android:id = "@+id/mapView" android:layout_width = "fill_parent" android:layout_height = "fill_parent" android:clickable = "true" android:apiKey = "0gtIEXVeu0g96nXpxjvByVW9hs7V0mDiuNHRwRw" /> </ LinearLayout > |
第三,将 GoogleMapExampleActivity 的继承类修改为 MapActivity,并添加 com.google.android.maps.MapActivity包,重写 isRouteDisplayed 方法,由于示例中没有正在显示的路线信息,这里我们返回 false 即可。
清单 4. GoogleMapExampleActivity 类
1 | public class GoogleMapExampleActivity extends MapActivity { @Override public void title="开发基于 Google Map 的 Android 应用" src="http://www.07net01.com/uploads/allimg/130329/16101SM8-7.png" width="480" height="800" />< P ></ P >< P >< STRONG >添加缩放控件并控制缩放比例,切换地图显示类型(卫星,地图,街道)</ STRONG ></ P >< P >Google 地图 MapView 对象自带有控制缩放比例的组件,我们可以通过调用 MapView 对象的 < EM >setBuiltInZoomControls</ EM >方法来完成添加或者移除缩放控件。</ P >< P >1.通过在 layout 文件 main.xml 中的 id 获取找到 MapView 对象</ P >< P >< STRONG >清单 5. 获取 MapView 对象</ STRONG ></ P >< PRE class = "brush: xml; gutter: true" >mapView = (MapView) findViewById(R.id.mapView);</ PRE >< P >2.在 mapView 对象上调用 setBuiltInZoomControls 方法,这里传入 boolean 类型的参数,true 和 false 分别表示添加或者移除缩放组件</ P >< P >< STRONG >清单 6. 调用 setBuiltInZoomControls 方法</ STRONG ></ P >< PRE class = "brush: xml; gutter: true" >mapView.setBuiltInZoomControls(true);</ PRE >< P >需要提到的是,如果添加了缩放控件,它会在第一次触击地图的时候生效,如图 9 所示。</ P >< P >< STRONG >图 9. 地图的缩放控件</ STRONG ></ P >< P >< IMG title = "开发基于 Google Map 的 Android 应用" class = "aligncenter size-full wp-image-22897" alt = "开发基于Google Map的Android应用" src = "http://www.07net01.com/uploads/allimg/130329/16101R396-8.png" width = 480 height = 800 ></ P >< P >通过 MapControl 来控制缩放比例,通过获取 MapView 的 MapControl 对象,控制缩放比例。这里我们设置 16 档为当前缩放大小。</ P >< P >< STRONG >清单 7. 控制缩放比例</ STRONG ></ P >< PRE class = "brush: java; gutter: true" >mapController = mapView.getController(); mapController.setZoom(16);</ PRE >< P >Google 地图缩放比例共分为 21 档,具体的缩放划分可以参考 google 文档,以及链接 http://greg-koppel.site88.net/maps/InfoDisplay.html</ P >< P >切换地图的显示类型,Google 地图提供了三种地图的显示方式,分别为卫星,地图,街道,默认设置为街道模式,这些模式的切换可以通过调用 MapView 对象提供的相应方法来完成切换。</ P >< P >最终的< A href = "http://www.07net01.com/program/" target = _blank >< U >代码</ U ></ A >示例:</ P >< P >< STRONG >清单 8. 切换地图的显示类型</ STRONG ></ P >< PRE class = "brush: java; gutter: true" >@Override public void>mapView = (MapView) findViewById(R.id.mapView); private LocationManager locationManager = null; private String bestProvider = null; private String getBestProvider(Context context){ Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_COARSE); // 设置精度 criteria.setAltitudeRequired(false); // 设置是否需要提供海拔信息 criteria.setBearingRequired(false); // 是否需要方向信息 criteria.setCostAllowed(false); // 设置找到的 Provider 是否允许产生费用 criteria.setPowerRequirement(Criteria.POWER_LOW); // 设置耗电 locationManager=(LocationManager)context.getSystemService(Context.LOCATION_SERVICE); String provider=locationManager.getBestProvider(criteria, true); // 这里可能返回 null, 地理位置信息服务未开启 return provider; } public Location getLastKnowLocation(Context context) { Location ret = null; this.bestProvider = getBestProvider(context); if(this.bestProvider != null) { ret = locationManager.getLastKnownLocation(this.bestProvider); } // 这里可能会返回 null, 表示按照当前的查询条件无法获取系统最后一次更新的地理位置信息 return ret; }</ PRE >< P >在实际应用中,这里有两个问题需要特别注意:</ P >< P >一方面,当 Android 设备的地理位置信息服务处于未开启的状态时,< CODE >通过</ CODE >LocationManager< CODE >获取的</ CODE >LocationProvider< CODE >将会返回</ CODE >null< CODE >,在这里需要提示用户当前地理位置信息服务未开启,否则将会有"</ CODE >< CODE >j</ CODE >ava.lang.IllegalArgumentException: provider==null< CODE >"</ CODE >< CODE >异常抛出</ CODE >< CODE >(</ CODE >< CODE >具体方式请参考</ CODE >< CODE >附带</ CODE >< CODE >源代码</ CODE >< CODE >)</ CODE >< CODE >。</ CODE ></ P >< P >另一方面,由于 getLastKnownLocation< CODE >方法是一个非阻塞调用方法,例如在设置为</ CODE >GPS< CODE >方式获取地理位置信息时经常会返回</ CODE >null,通常处理在 getLastKnownLocation< CODE >中返回值为</ CODE >null< CODE >的方法有两种</ CODE >< CODE >:</ CODE ></ P >< P >< CODE ></ CODE >< CODE >1.设置地理位置信息获取的精度为粗粒度位置信息获取,相对于</ CODE >< CODE >GPS</ CODE >< CODE >方式,通过网络信息等方式获取当前位置更容易进行定位。</ CODE ></ P >< PRE class = "brush: java; gutter: true" >criteria.setAccuracy(Criteria. ACCURACY_COARSE)</ PRE >< P >通过使用 LocationListener 请求并监听用户地理位置信息的变化</ P >< P >Step 1. 创建 Location Listener 对象,实现 LocationListener 接口</ P >< P >Step 2. 使用在 4.1 中初始化的 locationManager 对象请求地理位置信息的更新,并绑定到自己定义的 locationListener 对象</ P >< P >Step 3. 当 LocationManager< CODE >获取到有效的地理位置信息时,</ CODE >在 LocationListener 接口定义的>private MyLocationListener myLocationListener = null; public class MyLocationListener implements LocationListener { @Override public void title="开发基于 Google Map 的 Android 应用" src="http://www.07net01.com/uploads/allimg/130329/16101WA4-9.png" width="480" height="800" /></ P >< P >1.创建 MyOverlay 类,继承自 ItemizedOverlay 抽象类,在 MyOverlay 对象中包括所有要在地图上标注的对象列表 mItems。</ P >< P >2.重写 createItem 方法,将需要在地图上标注的点转化为 OverlayItem 对象,OverlayItem 对象对应于在地图上标注的每一个点,其包括经纬度信息、名称、标题、图标等属性,这些属性均可以通过其对象中提供的设置方法进行修改。</ P >< P >3.调用 < CODE >addMarker</ CODE >< CODE >()</ CODE >< CODE >方法,</ CODE >将获取的当前位置信息以图标方式显示在地图上。</ P >< P >4.在 < CODE >myMapOverlay</ CODE >< CODE >类中</ CODE >重写>private void addMarker() { if (myOverlay == null && myLocation != null) { GeoPoint myGeoPoint = location2GeoPoint(myLocation); if (myGeoPoint != null) { myOverlay = new MyMapOverlay(currLocMaker); myOverlay.setItem(myGeoPoint); mapView.getOverlays().add(myOverlay); mapController.animateTo(myGeoPoint); } } } public class MyMapOverlay extends ItemizedOverlay< OverlayItem > { private List< GeoPoint > mItems = new ArrayList< GeoPoint >(); public MyMapOverlay(Drawable marker) { // 初始化默认图标,并设置其为底部中心对应显示点 super(boundCenterBottom(marker)); } public void setItems(ArrayList< GeoPoint > items) { mItems = items; populate(); } public void setItem(GeoPoint item) { mItems.add(item); populate(); } @Override protected OverlayItem createItem(int i) { // 此处没有进行图标的修改,默认为使用父类的默认图标 return new OverlayItem(mItems.get(i), null, null); } @Override public int size() { return mItems.size(); } @Override protected boolean>本文通过实例介绍如何在 Android 系统上开发以及 Google Map 的简单应用程序,相信读者通过源代码实例以及文字介绍有了大致的了解。接下来我们还会对开发基于 Map 应用过程中一些常用的方法进行汇总,比如,如何自定制图标并添加文字,响应长按事件,zoom 事件,点击图标弹出气球框等。</ P > |