在第一讲的例子中,我们已经看到如何使用com.google.android,maps.MapView组件来开发一个简单的google地图程序,这一讲我们将看到,如何使用android手机自带的GPS系统来定位自己的位置,并在地图层中对此进行标识。

GPS 是英文Global Positioning System(全球定位系统)的简称,而其中文简称为“球位系”。GPS20世纪70年代由美国陆海空三军联合研制的新一代空间卫星导航定位系统 。其主要目的是为陆、海、空三大领域提供实时、 全天候和全球性的导航服务,并用于情报收集、核爆监测和应急通讯等一些军事目的经过20余年的研究实验,耗资300亿美元,到19943月,全球覆盖率高达98%24GPS卫星星座己布设完成。

我们在前面那个程序的基础上进行进一步的开发。

要在android程序中使用GPS进行开发,首先,必须在Manifest.xml文件中声明使用权限,在<application>元素外边添加如下的代码:

  1. <uses-permission android:name = "android.permission.ACCESS_FINE_LOCATION"/>
复制代码

接着,在MapView组件前面声明一些标签组件用于显示当前的经纬度信息:

  1. <TableLayout android:layout_width="fill_parent"
     
  2. android:layout_height="wrap_content" android:stretchColumns="1">
     
  3. <TableRow>
     
  4. <TextView android:layout_width="fill_parent"
     
  5. android:layout_height="wrap_content" android:text="GPS位置:" />
     
  6. </TableRow>
     

  7.  
  8. <TableRow>
     
  9. <TextView android:layout_width="fill_parent"
     
  10. android:layout_height="wrap_content" android:text="经度:" />
     

  11.  
  12. <TextView android:id="@+id/main_longitude"
     
  13. android:layout_width="fill_parent" android:layout_height="wrap_content" />
     
  14. </TableRow>
     

  15.  
  16. <TableRow>
     
  17. <TextView android:layout_width="fill_parent"
     
  18. android:layout_height="wrap_content" android:text="纬度:" />
     

  19.  
  20. <TextView android:id="@+id/main_latitude"
     
  21. android:layout_width="fill_parent" android:layout_height="wrap_content" />
     
  22. </TableRow>
     
  23. </TableLayout>
复制代码

上面的TableLayout是用于布局的组件,以后如果写布局方面的教程,在跟大家详细讲解吧。

然后,在程序里面添加一些用于控制经纬度信息显示的TextView私有域:

  1. private TextView textLongitude;//精度显示
     
  2. private TextView textLatitude;//纬度显示
复制代码

onCreat方法中对他们进行初始化:

  1. //通过ID初始化组件
     
  2. textLongitude = (TextView)findViewById(R.id.main_longitude);
     
  3. textLatitude = (TextView)findViewById(R.id.main_latitude);
复制代码

接着声明位置管理器,与位置信息监听器的组件:

  1. private LocationManager locationManager;//位置管理器
     
  2. private LocationListener locationListener;//位置监听器
复制代码

并在onCreat方法中分别对它们进行初始化:

  1. //从系统服务中获得位置管理器
     
  2. locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
     
  3. //初始化位置监听器
     
  4. locationListener = new LocationListener() {
     
  5. @Override
     
  6. public void onStatusChanged(String provider, int status, Bundle extras) {
     
  7. }
     

  8.  
  9. @Override
     
  10. public void onProviderEnabled(String provider) {
     
  11. }
     

  12.  
  13. @Override
     
  14. public void onProviderDisabled(String provider) {
     
  15. }
     

  16.  
  17. @Override
     
  18. public void onLocationChanged(Location location) {
     
  19. //当位置信息更新时,更新其位置信息的界面显示
     
  20. updateLocation(location);
     
  21. }
     
  22. };
复制代码

getSystemService方法时Activity的方法,用于或的系统的某些服务,这里我们获得的自然是GPS服务。实例域locationListener是一个位置信息监听器,它有四个方法,这里我们主要关心它的onLocationChanged方法,当位置信息发生变化时,该方法将被调用,这里,当位置信息发生变化时,我们自然是需要修改GPS坐标信息的,因此调用updateLocation方法,下面是它的定义:

 

  1. private void updateLocation(Location location) {
     
  2. if (location != null) {
     
  3. double longitude = location.getLongitude();// 经度
     
  4. double latitude = location.getLatitude();// 纬度
     

  5.  
  6. //刷新经纬度信息显示
     
  7. textLongitude.setText(longitude + "");
     
  8. textLatitude.setText(latitude + "");
     
  9. } else{
     
  10. textLongitude.setText("没有位置信息");
     
  11. textLatitude.setText("没有位置信息");
     
  12. }
     
  13. }
复制代码

再看下面一段定义在onCreat方法中的代码:

  1. //设置服务提供者,这里提供者设置为GPS卫星
     
  2. String provider = LocationManager.GPS_PROVIDER;
     
  3. Location location = locationManager.getLastKnownLocation(provider);//获得最新的位置
     
  4. updateLocation(location);//更新位置信息显示
     
  5. //设置监听器监听位置信息,最低的更新频率为3秒,位置跨度为10米
     
  6. locationManager.requestLocationUpdates(provider, 3000, 10, locationListener);
复制代码

这段代码设定GPS位置信息的提供者为GPS卫星,并尽快显示上一次GPS服务所得到的位置信息,最后一段代码相当于是在注册监听器,设置其最低的更新频率为3秒,位置跨度为10米。

注意,因为本程序使用了GPS服务,所以在使用本程序之前得提前打开手机的GPS服务。一般是在:设置à位置,然后在使用GPS卫星项打钩。



 

现在关于GPS部分就差不多讲完了,但是程序目前还没有和Map组件关联起来,在之后我们将看到如何使用地图层类在地图中进行标识。


 今天我们来看一下如何将得到的GPS位置用于google地图中进行定位,首先我们得了解什么事图层类(Overlay),该类是一个描述了将呈现在地图顶层的地图层的基类,如果我们要给地图新添加一个图层,首先得继承这个类,然后创建一个它的实例,将它添加到MapView.getOverlays()返回的Overlay线性表中去。

因此,本程序首先增加一个类MyLocationOverlay,该类继承了Overlay,定义一个该类的构造方法:

  1. public MyLocationOverlay(Resources res){
     
  2. this.res = res;
     
  3. }
复制代码

res是我们自己定义的一个Resources类型的实例域,用于获得将要显示的图片资源,接着再增加两个实例域:

  1. private Double longitude;//经度
     
  2. private Double latitude;//纬度
复制代码

用于存放经纬度位置信息,接着设置一个可以set他们的方法:

  1. //在更新坐标时,设置该坐标,以便画图
     
  2. public void setLocation(double longitude, double latitude) {
     
  3. this.longitude = longitude;
     
  4. this.latitude = latitude;
     
  5. }
复制代码

重写父类的draw方法,当更新地图时,它将被调用。
  1. @Override
     
  2. public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
     
  3. super.draw(canvas, mapView, shadow);
     

  4.  
  5. //GPS服务没有开通或不支持
     
  6. if(longitude == null || latitude == null)
     
  7. return false;
     

  8.  
  9. // 将经纬度转换成实际地图坐标
     
  10. GeoPoint tmpGeoPoint = new GeoPoint((int)(latitude * 1E6), (int)(longitude * 1E6));
     

  11.  
  12. //将地图坐标转换位屏幕位置
     
  13. Point myScreenCoords = new Point();
     
  14. mapView.getProjection().toPixels(tmpGeoPoint, myScreenCoords);
     

  15.  
  16. //设置画笔格式
     
  17. Paint paint = new Paint();
     
  18. paint.setStrokeWidth(1);
     
  19. paint.setARGB(255, 255, 0, 0);
     
  20. paint.setStyle(Paint.Style.STROKE);
     

  21.  
  22. //添加地图层
     
  23. Bitmap bmp = BitmapFactory.decodeResource(res, R.drawable.icon);
     
  24. canvas.drawBitmap(bmp, myScreenCoords.x, myScreenCoords.y, paint);
     
  25. canvas.drawText("Here am I", myScreenCoords.x, myScreenCoords.y, paint);
     
  26. return true;
     
  27. }
复制代码

在添加地图层时或得的图片资源是用于标识你的位置所在,你可以自己找图片放进drawble文件中去,然后在这里解码它们,这里为了省麻烦就直接用系统的那个图片了。

接下来,在主类中我们再添加两个实例域:

  1. private MapController mMapController;// 地图管理器
     
  2. private MyLocationOverlay myPosition;// 我的位置图层
复制代码

在onCreat方法中我们首先要获得对地图组件的引用,然后分别对他们进行初始化:

  1. MapView mMapView = (MapView) findViewById(R.id.main_MapView);
     

  2.  
  3. mMapController = mMapView.getController();// 获得地图管理器
     
  4. mMapController.setZoom(17);// 设置缩放等级
     

  5.  
  6. myPosition = new MyLocationOverlay(getResources());// 初始化我的位置图层
     
  7. List<Overlay> list = mMapView.getOverlays();// 获得地图层集合
     
  8. list.add(myPosition);// 将我的位置图层加入该地图层集合
复制代码

当地图更新时,list中的所有图层都会被调用draw方法,重新绘制图层。

注意,这段代码必须放在updateLocation(location);的前面,因为我们接下来将往其中添加更新地图层的代码,否则会抛出空指针异常。

在updateLocation中新增的代码:

  1. // 更新地图显示
     
  2. myPosition.setLocation(longitude, latitude);// 设置我的位置
     
  3. GeoPoint point = new GeoPoint((int) (latitude * 1E6),
     
  4. (int) (longitude * 1E6));// 获得经纬度点
     
  5. mMapController.animateTo(point);// 地图指向新的坐标
复制代码

没当GPS位置信息更新后,就会重新绘制地图层更新你的位置,下面是运行示例: