第23回位置与地图,从此不再路痴

来源:互联网 发布:怎么把源码变成软件app 编辑:程序博客网 时间:2024/04/27 19:24

这一日,刘关张三人闲来无事,坐在院子里烤鸡翅膀,正烤到兴高采烈,手舞足蹈之际,忽听得墙外有一阵异响!刘备被吓了一跳,手里的鸡翅膀差点掉了下来,“什么声音?打雷吗?”

关羽捋了捋胡子:“打雷不会这么难听吧,好像响声不远,就在附近!”

刘备:“曹操来砸场子吗?”

张飞:“大哥,你别神神叨叨的好不好,你当演古惑仔呢。有什么事看看不就知道了嘛。”

三人一出门,只见一彪形大汉瘫倒在墙边,手捂着肚子,有气无力地说:“给……给口饭吃……思密达!”

张飞撇了撇嘴:“哦,是个棒子,咱是装作没看见呢,还是装作什么都没看见呢?”

嘴上虽这么说,但三人还是把这汉子拖到了院内,喂了鸡翅膀吃。哪知此人吃了鸡翅膀之后,立刻变得生龙活虎起来,“在下孟获,多谢各位相救的思密达!”

刘备抹了抹夺眶而出的眼泪:“原来你就是孟获,久违久违,我还以为死了都见不到你呢~”

张飞怒道:“你好好的一个南蛮,怎么老思密达思密达的?”

孟获:“唉,多怪我老婆太爱看韩剧,染上了这臭毛病的思密达。”

关羽:“孟兄何故到此啊?莫非要南蛮入侵?”

孟获:“郁闷啊,那天跟老婆吵架,被赶出来了,走着走着走歪了,就走到这儿来了思密达。”

刘备感叹道:“壮士生的一副好腿脚啊!”

孟获:“都怪我天生路痴啊,这怎么回家都是个问题啊!思密达呀嘛思密达!”说着嗷嗷大哭起来。

刘备:“壮士休要哭泣,待我三人给你做个导航应用,就不愁找不到家啦!”

孟获抱住刘备的大腿,说道:“先别说这个,鸡翅膀还有吗的思密达?”

1.1. 位置与地图简介

近年来,由于移动互联网的快速发展,基于位置服务的应用也百花绽放,例如,地图、导航、位置交友,微信!基于位置的服务,又称定位服务,简称LBS(Location Based Service),指的是通过采用无线定位、GPS、Internet和无线通信等技术,确定移动用户的地理位置,为应用提供位置信息的一种综合业务。

位置信息的呈现方式是较为抽象的,而用户更愿意看到直观的信息表达。最常见的地图应用,它将用户的位置直观地呈现在地图上,让人们体会到了高科技的奥妙。本节将详细讲解Android中如何使用位置API和开发地图应用。

1.2. 位置服务

Android提供了一组支持地理定位的API。地理定位API可以用来获取当前设备的地理位置。应用程序可以通过定时请求更新设备当前的地理位置信息或借助Intent接收器来实现对用户的经纬度地理信息的实时获取。在下面的内容中,首先讲解android.location中定位有关的类,然后通过一个简单实例,演示如何获取用户的地理信息。

1.2.1.LocationManager

Android中的LocationManager提供了一系列方法来处理地理位置相关的事务,包括查询上一个已知位置;注册/注销来自某个LocationProvider周期性的位置更新服务;注册/注销接近某个坐标时对一个已定义Intent的触发服务等。

要创建LocatinManager,需要通过下面这种方式来获取,直接实例化LocationManager是不允许的。

LocationManagerlocationManager

= (LocationManager) getSystemService(Context.LOCATION_SERVICE); 

得到了LocationManager的实例以后,就可以通过下面的语句来注册一个周期性的位置更新服务:

locationManager.requestLocationUpdates

(LocationManager.GPS_PROVIDER, 1000, 0, locationListener); 

上面代码表示从GPS中获取位置信息,每隔1000ms更新一次,并且不考虑位置的变化。LocationManager的静态常量和方法如表23-1所示:

表23-1 LocationManager的静态常量和方法

静态常量和方法

说明

static String GPS_PROVIDER

静态字符串常量,表明LocationProvider通过GPS定位。

static String NETWORK_PROVIDER

静态字符串常量,表明LocationProvider通过网络定位。

boolean addGpsStatusListener(GpsStatus.Listener listener)

添加一个GPS状态监听器。

void requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener)

通过给定的Provider名称,周期性地通知当前Activity。

void addProximityAlert(double latitude, double longitude, float radius, long expiration, PendingIntent intent)

添加一个趋近警告。

void removeProximityAlert(PendingIntent intent)

删除趋近警告。

List<String> getAllProviders()

获得所有LocationProvider列表。

String getBestProvider(Criteria criteria, boolean enabledOnly)

根据Criteria返回最适合的LocationProvider。

Location getLastKnownLocation(String provider)

根据Provider获得位置信息。

LocationProvider getProvider(String name)

获得指定名称的LocationProvider。

List<String> getProviders(boolean enabledOnly)

获得可利用的LocationProvider列表。

刘备:LocationManager.NETWORK_PROVIDER使用移动网络定位,精度较低但速度较快;LocationManager.GPS_PROVIDER使用GPS定位,精度很高但一般需要10-60秒才能开始第1次定位,如果在室内基本上无法定位。这2种Provider本质上是互补的。

 

 

 

 

1.2.2.LocationProvider

LocationProvider用来描述定位提供者,设置定位提供者的一些属性。可以通过Criteria类来为LocationProvider设置条件,获得合适的LocationProvider。定位提供者LocationProvider一般是GPS、Network和passive定位组件的表示,应用程序中的定位信息都由它来提供。不同的LocationProvider决定了不同的定位能力,包括费用、耗电、精确度、速度等。LocationManager提供了一个getAllProviders()方法用于获取系统所有可用的LocationProvider。获取当前可以利用的LocationProvider如下代码所示:

//通过getSystemService方法获得LocationManager实例

LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE); 

//LocationProvider的两种方式

String name = LocationManager.GPS_PROVIDER; 

String name2 = LocationManager.NETWORK_PROVIDER; 

//根据Provider名称获得LocationProvider  

LocationProvider myProvider= locationManager.getProvider(name); 

boolean enabledOnly = true; 

//获得所有可利用的Provider名称列表

List<String> providers = locationManager.getProviders(enabledOnly); 

//根据名称获得Provider  

myProvider = locationManager.getProvider(name);

 

LocationProvider的静态常量和方法如表23-2所示:

 

 

 

 

表23-2 LocationProvider的静态常量和方法

静态常量和方法

说明

static int AVAILABLE

静态整型常量,标示是否可利用。

static int OUT_OF_SERVICE

静态整型常量,不在服务区。

static intTEMPORARILY_UNAVAILABLE

静态整型常量,临时不可利用。

abstractint getAccuracy()

获得经度。

String getName()

获得名称。

abstractint getPowerRequirement()

获得电源需求。

abstractboolean hasMonetaryCost()

设置付费还是免费。

abstractboolean requiresCell()

是否需要访问基本网络。

abstractboolean requiresNetwork()

是否需要Internet网络数据。

abstractboolean requiresSatellite()

是否需要访问卫星。

abstractboolean supportsAltitude()

是否能够提供高度信息。

abstractboolean supportsBearing()

是否能够提供方向信息。

abstractboolean supportsSpeed()

是否能够提供速度信息。

1.2.3.LocationListener

LocationListener类用于接收从LocationManager位置发生改变时的通知。在LocationManager对象中调用了requestLocationUpdates(String, long, float, LocationListener)方法,将LocationListener注册添加到LocationManager对象中,当LocationManager位置发生改变时,此接口中的相关方法将会被调用。LocationListener类主要有四个方法:

l  public abstract void onLocationChanged(Location location):当位置发生改变后被调用。

l  public abstract voidonProviderDisabled(String provider):在LocationProvider被用户关闭后被调用。

l  public abstract void onPorviderEnabled(Location location):在LocationProvider被用户开启后调用。

l  public abstract void onStatusChanged(String provider, int Status, Bundle extras):当LocationProvider在可用、暂时不可用和无服务三个状态直接切换时被调用。

1.2.4.Location

Location类用于描述当前设备的地理位置信息,包括了经纬度、方向、高度和速度等,可以通过LocationManager.getLastKnownLocation(String provider)方法获得Location实例。Location常见方法有:

表23-3 Location常见方法

方法名称

说明

float getAccuracy()

获得精确度。

double getAltitude()

获得高度。

double getLatitude()

获得纬度。

double getLongitude()

获得经度。

float getBearing()

获得方向。

float getSpeed()

获得速度。

1.2.5.Criteria

Criteria用于设置一系列的查询条件,可以根据这些指定的Criteria条件过滤LocationProvider,如下代码所示:

// Criteria 设置条件来选择合适的定位提供者示例代码

LocationManager locationManager =

 (LocationManager) getSystemService(Context.LOCATION_SERVICE);  

Criteria criteria = new Criteria();  

//设置精确度

criteria.setAccuracy(Criteria.ACCURACY_COARSE);  

//设置电耗

criteria.setPowerRequirement(Criteria.POWER_LOW);    

//是否需要高度信息 

criteria.setAltitudeRequired(false);  

//是否需要方位信息

criteria.setBearingRequired(false);     

//是否需要速度信息

criteria.setSpeedRequired(false);  

//是否产生费用

criteria.setCostAllowed(true);     

//获得符合条件的最好Provider  

String bestProvider = locationManager.getBestProvider(criteria, true);  

//获得符合条件的Provider  

List<String> matchingProviders = locationManager.getProviders(criteria, false);  

           上述代码设置了一个粗精度、低电耗,不需要高点、方位、速度,但需要收费的Criteria。通过LocationManager.getBestProvider()方法获得最符合条件的位置提供者LocationProvider;通过LocationManager.getProviders()方法获得所有符合条件的LocationProvider。

1.2.6.Geocoder

Geocoder类是一个处理前向地理编码和反向地理编码的类。地理编码是一个街道、地址或者其他位置转化为坐标的过程。反向地理编码是将坐标转换为地址的过程。Geocoder类要求的后台服务并没有包含在基本的Android框架中。如果没有此后台服务,执行Geocoder的查询方法将返回一个空列表。可以使用isPresent()方法确定Geocoder类是否能够正常执行。其他常用的Geocoder类方法如下:

l  public List<Address>getFromLocation(double latitude, double longitude, int maxResults):根据给定的经纬度返回一个描述此区域的地址数组,maxResults表示要返回结果的最大数。

l  public List<Address>getFromLocationName(String locationName, int maxResults):返回一个由给定的位置名称参数所描述的地址数组。

l  public List<Address> getFromLocationName(StringlocationName, int maxResults, double lowerLeftLatitude, doublelowerLeftLongitude, double upperRightLatitude, double upperRightLongitude):返回一个由给定的位置名称参数所描述的地址数组。名称参数可以是一个位置名称。可以指定一个搜索边界框,该边界框由左下方坐标经纬度和右上方坐标经纬度确定。

刘备:一组反向地理编码结果可能会有所差异。例如:一个结果可能包含最临近建筑的完整街道地址,而另一个可能只包含城市名称和邮政编码。

 

 

 

 


1.2.7.位置服务实例

本节我小飞飞要通过一个简单的实例,演示如何获得我小飞飞的地理位置信息。我主要使用了LocationManager和LocationListener两个类。下图23-1显示了运行效果图:

图23-1 获取地理位置信息效果图

           例子定义了一个Button按钮,当点击按钮时,程序首先判断当时GPS和网络哪个可用,从可用的组件中获取当前时间、经度、纬度和海拔信息。

           新建一个Activity,命名为MainActivity,代码如下所示:

MainActivity.java代码清单23-2-7:

/**

*@anthor张飞:我能抵抗一切,除了诱惑……

*/

public class MainActivity extendsActivity{

private TextViewinfoView=null; 

           privateTextView locationView=null; 

           privateButton button=null; 

           privateOnClickListener buttonListener = null;

//位置管理器

privateLocationManager locationManager=null; 

//位置监听器

privateLocationListener locationListener=null; 

public voidonCreate(Bundle savedInstanceState) { 

super.onCreate(savedInstanceState); 

                     setContentView(R.layout.main);

               infoView=(TextView)findViewById(R.id.infoView); 

               locationView=(TextView)findViewById(R.id.locationView);

               init(); 

}     

private void init(){

/*初始化按钮和按钮监听*/

               button=(Button) findViewById(R.id.button);

                     buttonListener= new OnClickListener() {

public voidonClick(View v) {

                                          getLocation();

                       }

                   };

                     button.setOnClickListener(buttonListener);

                     /*locationManager初始化*/

locationManager=

(LocationManager)this.getSystemService(Context.LOCATION_SERVICE);         

               } 

                     privatevoid getLocation() {

                                /*判断GPS是否可用*/

                                if(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){

locationListenerInit();                                                                        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,1000,0,locationListener); 

                                          setTitle("GPS定位");

                                }/*判断网络是否可用*/ 

                                elseif(locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)){

                                                  locationListenerInit();locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,1000,0,locationListener); 

                                          setTitle("网络定位");

                                }/*GPS和网络都不可用*/

                                else{

                                          setTitle("当前GPS和网络都不可用!");

                                }

                     }

               /*locatonListener初始化*/ 

               void locationListenerInit(){ 

                   locationListener=newLocationListener(){ 

                       //位置变化时触发

                       public voidonLocationChanged(Location location) { 

                           locationView.setText("时间:"+new Timestamp(location.getTime())+"\n"); 

                           locationView.append("经度:"+location.getLongitude()+"\n"); 

                           locationView.append("纬度:"+location.getLatitude()+"\n"); 

                           locationView.append("海拔:"+location.getAltitude()+"\n"); 

                       } 

                       //禁用时触发

                       public voidonProviderDisabled(String provider) { 

                           infoView.setText("当前位置提供者状态:禁用\n"); 

                       } 

                       //开启时触发

                       public voidonProviderEnabled(String provider) { 

                           infoView.setText("当前位置提供者状态:开启\n"); 

                       } 

                       //状态变化时触发

                       public void onStatusChanged(Stringprovider, int status,Bundle extras) { 

                          if(status==LocationProvider.AVAILABLE){ 

                               infoView.setText("当前位置提供者状态:可见的\n"); 

                           }elseif(status==LocationProvider.OUT_OF_SERVICE){ 

                               infoView.setText("当前位置提供者状态:服务区外\n"); 

                           }elseif(status==LocationProvider.TEMPORARILY_UNAVAILABLE){ 

                               infoView.setText("当前位置提供者状态:暂停服务\n"); 

                           } 

                       } 

                   }; 

               } 

}

           MainActivity通过设置位置监听器LocationListener,当位置发生变化时,触发onLocationChanged()方法。方法将当前的时间、经纬度、海拔位置信息,在TextView中显示出来。值得注意的是,工程需要在配置文件中添加权限:

<uses-permissionandroid:name="android.permission.ACCESS_FINE_LOCATION"/>

1.3. 地图服务

相信大家现在出差或者旅游时,都会事先通过Web上的地图进行路线的查询。地图服务已经被内置在手机、平板等多种移动终端上。目前常见的地图服务有:谷歌地图、百度地图、普加地图和搜狗地图。虽然地图服务有多个服务提供者,但应用内置地图服务的开发过程是相似的。这些地图服务都提供了丰富的数据信息接口,如搜索、路线规划等。这些接口使得我们可以在自己的应用程序中开发地图服务。

众所周知,Android是谷歌推出的手机操作系统,谷歌提供了一组访问地图的API,用于查询地形地貌、建筑道路的信息。但是由于谷歌地图显示多个图层,使得界面有些混乱、昏眩。相对谷歌地图,百度地图更加的贴近我们的生活。百度地图覆盖了国内数千个区县,400多个城市。我们可以查询街道、商店、公园、银行等地理位置。下面我们为了能够让读者学习如何利用第三方服务开发一个地图应用,将通过一个地图应用实例学习如何开发地图应用。

1.3.1.地图开发环境搭建

百度地图Android SDK可以适用于Android 移动设备的地图开发。使用百度Android SDK,首先需要有百度帐号。拥有百度帐号的开发者,可以直接申请百度地图所需的密钥http://developer.baidu.com/map/android-mobile-apply-key.htm,如图23-2所示:

图23-2 申请地理服务密钥过程

申请完密钥,就可以使用百度提供的SDK接口了,如图23-3所示:

图23-3 申请地理服务密钥结果

申请完密钥之后就可以将其添加到应用程序中使用了。由于百度API是作为第三方插件的方式加入到项目中,所以需要在工程中添加百度地图的的API包。百度地图API包包含一个jar包和一个“.so”文件。使用百度地图API包时,需将这两个文件拷贝到项目的libs文件夹下,同时新建一个armeabi文件夹,将“.so”文件放在该文件夹下,如图23-4所示:

图23-4 添加开发包

最后,因为地图开发需要访问服务器和自适应屏幕,所以配置文件中需添加网络访问权限和支持多屏幕机制,代码如下所示:

           <!--允许程序访问有关GSM网络信息 -->

<uses-permissionandroid:name="android.permission.ACCESS_NETWORK_STATE" />

           <!--允许一个程序访问精确位置 -->

           <uses-permissionandroid:name="android.permission.ACCESS_FINE_LOCATION" />

           <!--允许程序访问网络 -->

           <uses-permissionandroid:name="android.permission.INTERNET" />

           <!--允许程序写入外部存储 -->

           <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE" />

           <!--允许程序访问Wi-Fi网络状态信息 -->

           <uses-permissionandroid:name="android.permission.ACCESS_WIFI_STATE" />

           <!--允许程序改变WiFi状态清除应用缓存 -->

           <uses-permissionandroid:name="android.permission.CHANGE_WIFI_STATE" />

           <!--允许程序读取电话状态访问电话状态 -->

           <uses-permissionandroid:name="android.permission.READ_PHONE_STATE" />

           <!--用于支持多屏幕机制-->

           <supports-screensandroid:largeScreens="true"

android:normalScreens="true"android:smallScreens="true"

android:resizeable="true"android:anyDensity="true"/>

<!—Android版本支持-->

<uses-sdkandroid:minSdkVersion="3"></uses-sdk>

           通过上述的配置就完成了在应用程序中使用一个第三方地图服务的配置。下面几节将讲解在使用百度地图服务开发时,常用到的百度地图SDK提供的类。

1.3.2.MapView

为了让应用程序添加地图功能的过程变得简单,第三方地图提供者一般都提供了地图视图类MapView。百度地图包中的关键类com.baidu.mapapi.MapView,它是ViewGroup的一个子类。MapView类显示从地图服务器获取的数据。当MapView获取焦点时,它会获取键盘响应、触摸手势事件,根据手势自动缩放地图。同时它也提供了用户用来控制地图的所有的必要UI元素。

刘备:MapView必须和MapActivity配合使用,而且只能被MapActivity创建。这是因为MapView需要通过后台的线程来连接网络或者文件系统,而这些线程需要MapActivity来管理。

 

 

 

 

 


MapView类提供了地图API的一个封装,使应用程序通过类的方法操作地图数据。它可以像其他View一样来操作地图数据。MapView组件的使用方式,首先在xml布局文件里面定义组件,代码如下所示:

<MapView

           android:id=”@+id/mapview”

           android:layout_width=”fill_parent”

           android:layout_height=”fill_parent”

           android:clickable=”true” />

其次在Activity中创建MapView组件:MapView mapView=(MapView)findViewById(R.id.mapview),然后就可以通过mapView操控MapView了。百度地图MapView类常用方法如下表23-4所示:

表23-4 MapView类常用方法

方法名

说明

MapController getController()

返回地图的MapController,该类可用于控制平移和缩放。

intgetLatitudeSpan()

当前纬线的跨度,从地图的上边缘到下边缘。

intgetLongitudeSpan()

当前经度的跨度,从地图的左边缘到地图的右边缘。

void  setBuiltInZoomControls(boolean on)

设置是否启用内置的缩放控件。如果启用,MapView将自动缩放这些控件,默认启用缩放控件。

void  setDragMode(int mode)

设置当前拖拽模式,默认值为0。0:拖拽有动画;1:拖拽无动画。

GeoPoint getMapCenter()

返回当前地图中心点位置,做为一个GeoPoint(经度、纬度)的对象。

int getMaxZoomLevel()

返回当前视图中心点的最大缩放级别。

List<Overlay> getOverlays()

获取Overlay列表。

boolean isFinishLoaded()

地图是否加载完成。

void  setDraggable(boolean draggable)

设置是否允许拖动地图,默认允许拖动。

void  setSatellite(boolean on)

设置地图模式为“卫星”模式,装载带有道路名称的俯拍图像块。

void setTraffic(boolean on)

控制是否在地图上显示实时的交通信息。

void  regMapViewListener(BMapManager bmapMan, MKMapViewListener listener)

注册地图显示事件监听器。

1.3.3.MapActivity

MapActivity类是用于显示Map的Activity类,它需要连接底层网络。MapActivity是一个抽象类,任何想要显示MapView的Activity都需要派生自MapActivity,并且在其派生类的onCreate()中,创建一个MapView实例。MapActivity的主要功能有:(1)管理Activity的生命周期;(2)为MapView类建立和撤消相关的服务。

MapActivity相对其他Activity多出了以下方法:

l  protected booleanisLocationDisplayed():返回是否显示位置信息。

l  protected abstract booleanisRouteDisplayed():返回是否正在显示路线信息。

1.3.4.MapController

MapController是一个工具类,用于控制地图的缩放和平移。可以使用getController()方法获得MapView的控制器,如下面的代码所示:MapController mapController=myMapView.getController()。MapController常见的方法如下表23-5所示:

 

 

表23-5 MapController常见的方法

方法名

说明

void animateTo(GeoPoint geoPoint)

对输入参数GeoPoint,开始动画显示地图。

void animateTo(GeoPoint geoPoint, Message message)

对输入参数GeoPoint,开始动画显示地图。

void setCenter(GeoPoint geoPoint)

在给定的中心点GeoPoint上设置地图视图。

int setZoom(int zoomLevel)

设置地图的缩放级别(zoomLevel + 1)。

void zoomIn()

缩小一个级别。

void zoomInFixing(int xPixel, int yPixel)

放大一个级别,同时把地图平移到屏幕的一个固定点上。通过像素坐标来设定固定点。

void zoomOut()

放大一个级别(zoomLevel – 1)。

void zoomOutFixing(int xPixel, int yPixel)

缩小一个级别,同时把地图平移到屏幕的一个固定点上。通过像素坐标来设定固定点。

void zoomToSpan(int latSpanE6, int lonSpanE6)

尝试调整地图的缩放,以便显示给定的经纬度范围。

1.3.5.BMapManager

BMapManager是地图引擎管理类,负责管理地图搜索、位置定位、路线查询等功能。BMapManager提供以下方法:

l  void destroy():当程序退出时调用。

l  MKLocationManager getLocationManager():获取定位服务管理类。

l  boolean init(String strKey, MKGeneralListener listener):用申请的授权验证码对BMapManager进行初始化,并注册回调事件。

l  boolean start():开启百度地图API。

l  boolean stop():终止百度地图API,调用此方法后,不会再发生回调。

上述init()方法中使用了MKGeneralListener接口。该接口一般用于返回网络状态和授权验证结果。创建该接口对象时,需要重写该接口处理事件的两个方法:

l  void onGetNetworkState(int iError):当网络发生错误时需要处理的事件。

l  void onGetPermissionState(int iError):当授权验证错误时需要处理的事件。

BMapManager对象的初始化消耗资源较大,建议在Application里生成BMapManager对象,在程序退出时调用destory()方法销毁对象,然后在需要使用地图服务的Activity里的onCreate()方法里调用start()方法开启百度地图API,并通过onDestroy()方法调用stop()方法终止百度地图API。

1.3.6.Overlay

Overlay是一个基类,它表示可以覆盖在地图上方显示的一个图层,可以添加单击事件。当添加一个Overlay时,可以从该基类派生出一个子类,创建一个实例,然后把它加入到列表中,可以通过MapView.getOverlays()方法得到该列表。每一个Overlay都可以直接在画布上绘制2D图形,包括文本、直线、图片和各种形状,之后这些2D图形会覆盖到MapView上。

可以向一个地图中添加多个Overlay。添加新的Overlay时,需要通过扩展Overlay来创建一个新的类,然后重写其中的draw()方法来绘制希望添加的注释,并重写onTap()方法响应用户的单击事件(通常是当用户单击这个Overlay添加的注释时产生的事件)。下面介绍这两种方法:

l  public void draw(Canvas canvas, MapView mapView, boolean shadow):负责在地图上绘画。

l  public boolean onTap(GeoPoint point, MapView mapView):处理一个点击事件。

Overlay地图覆盖物可以叠加或覆盖到地图现有内容上。覆盖物一般拥有自己的地理坐标,当拖动或缩放地图时,它们会相应的移动。百度地图API除了提供Overlay覆盖物基类外,还提供了如下覆盖物:

l  MyLocationOverlay:负责显示用户当前位置的Overlay。

l  ItemizedOverlay<Item extends OverlayItem>:Overlay的一个基类,包含了一个OverlayItem列表,相当于一组Overlay,通过继承此类,将一组标注点显示在地图上。

l  PoiOverlay:本地搜索图层,提供某一特定地区的位置搜索服务,比如在北京市搜索“公园”,通过此图层将公园显示在地图上。

l  RouteOverlay:步行、驾车导航线路图层,将步行、驾车出行方案的路线和关键点显示在地图上。

l  TransitOverlay:公交换乘线路图层,将某一特定地区的公交出行方案的路线和换乘位置显示在地图上。

1.3.7.GeoPoint

GeoPoint表示一个地理坐标点,用于存放经度和纬度,以微度的整数形式存储,可以用于地图位置的定位。主要有以下方法:

l  boolean equals(Object obj):地理位置坐标比较,当且仅当两个GeoPoint对象的的经纬度都相同时返回true。

l  int getLatitudeE6():返回GeoPoint对象的纬度(微度)。

l  int getLongitudeE6():返回GeoPoint对象的经度(微度)。

1.3.8.地图服务实例

本节我小飞飞主要通过调用上述所说的类,实现一个地图上包含我、大哥刘备、二哥关羽图片覆盖物的地图,点击覆盖物出现当前的经纬度坐标。程序的运行结果如图23-5所示:

图23-5 地图实例

例子中,显示了张飞、关羽、刘备的图片,当点击图片时,可以获取点击人物当前的经度、纬度信息。

新建一个Activity,命名为MainActivity,其代码如下所示:

MainActivity.java代码清单23-3-8:

/**

*@author张飞:虽然木有方向感,但是我有地图!

*/

public class MainActivity extends MapActivity {

           //添加百度地图的MapView视图控件

           private MapViewmapView;

           //加载地图的引擎

           private BMapManagerbMapManager;

           //百度地图的key

           private StringKeyString = "37801F039621A019972BEB530C48009E50A208C0";

           //在百度地图上添加一些控件,例如,放大或者缩小的控件

           private MapControllermapController;

    @Override

    public voidonCreate(Bundle savedInstanceState) {

       super.onCreate(savedInstanceState);

       setContentView(R.layout.main);

        //获取MapView视图空间类

        mapView = (MapView)this.findViewById(R.id.bmapView);

        bMapManager = newBMapManager(MainActivity.this      );

        //必须要加载key

       bMapManager.init(KeyString, new MKGeneralListener() {

                                //授权验证错误

                                publicvoid onGetPermissionState(int arg0) {

                                          if(arg0==300){

                                                     Toast.makeText(MainActivity.this,"输入的key有错,请核实!!", 1).show();

                                          }

                                }

                                //网络错误

                                publicvoid onGetNetworkState(int arg0) {

                                              Toast.makeText(MainActivity.this, "当前网络不可用!!", 1).show();

                                }

                     });

       this.initMapActivity(bMapManager);

        //表示可以设置缩放功能

       mapView.setBuiltInZoomControls(true);

        mapController =mapView.getController();

        //设置缩放级别为12个级别

       mapController.setZoom(12);

        //获取覆盖类的图片

        Drawable drawable =getResources().getDrawable(R.drawable.zhangfei);

        //添加一组覆盖类

       mapView.getOverlays().add(new MyOverLayItem(drawable));、

    }

    /**

     * @author 张飞

     * 一个OverlayItem列表,将一组标注点显示在地图上

     */

    public class MyOverLayItemextends ItemizedOverlay<OverlayItem>{

           privateList<OverlayItem> list = new ArrayList<OverlayItem>();

           //以double类型定义一组坐标

           private double mLat1= 39.90923;//表示为纬度

           private double mLon1= 116.397428;//表示经度

           private double mLat2= 39.9032;//表示为纬度

           private double mLon2= 116.3922;//表示经度  

           private double mLat3= 39.9053;//表示为纬度

           private double mLon3= 116.3933;//表示经度

           //用于在地图上标识坐标,用一个图片标注

           publicMyOverLayItem(Drawable arg0) {

                     super(arg0);

                     //第一组数据在地图上的标注点

                     GeoPointgeoPoint1  = newGeoPoint((int)(mLat1*1E6),(int)(mLon1*1E6));

                                //第二组数据在地图上的标注点

                     GeoPointgeoPoint2  = new GeoPoint((int)(mLat2*1E6),(int)(mLon2*1E6));

                                //第三组数据在地图上的标注点

                     GeoPointgeoPoint3  = newGeoPoint((int)(mLat3*1E6),(int)(mLon3*1E6));

                     //标注点、标题、片段

                     OverlayItemmOverlayItem=

new OverlayItem(geoPoint1,"point1",

"纬度:"+geoPoint1.getLatitudeE6()+

" 经度:"+geoPoint1.getLongitudeE6());

                                list.add(mOverlayItem);

                   Drawable drawable =getResources().getDrawable(R.drawable.liubei);

                   mOverlayItem=

newOverlayItem(geoPoint2,"point2",

"纬度:"+geoPoint2.getLatitudeE6()+

" 经度:"+geoPoint2.getLongitudeE6());

                   mOverlayItem.setMarker(drawable);

                                list.add(mOverlayItem);

                   drawable =getResources().getDrawable(R.drawable.guanyu);

                   mOverlayItem=

newOverlayItem(geoPoint3,"point3",

"纬度:"+geoPoint3.getLatitudeE6()+

" 经度:"+geoPoint3.getLongitudeE6());

                   mOverlayItem.setMarker(drawable);

                                list.add(mOverlayItem);

                                //地图刷新的功能

                                populate();

                     }

                     //返回指定的list集合中每一个坐标

                     @Override

                     protectedOverlayItem createItem(int arg0) {

                                returnlist.get(arg0);

                     }

                     //返回list集合中坐标的个数

                     @Override

                     public intsize() {

                                returnlist.size();

                     }

                     //当点击时弹出Toast

                     @Override

                     publicboolean onTap(int i) {

                                Toast.makeText(MainActivity.this,list.get(i).getSnippet(), 1).show();

                                returntrue;

                     }

    }   

    //当Activity销毁时,MapManager也随之销毁

    @Override

    protected void onDestroy(){

                      super.onDestroy();

                      if(bMapManager!=null){

                                bMapManager.destroy();

                                bMapManager = null;

                      }

    }

    //当Activity启动时,MapManager也随之启动

    @Override

    protected void onResume(){

                      super.onResume();

                      if(bMapManager!=null){

                                bMapManager.start();

                      }

    }

    //当Activity暂停时,MapManager也随之停止

    @Override

    protected void onPause() {

                      super.onPause();

                      if(bMapManager!=null){

                                bMapManager.stop();

}

    }

           @Override

           protected boolean isRouteDisplayed(){

                     returnfalse;

           }

}

该MainActivity主要使用了ItemizedOverlay。 ItemizedOverlay可以将标记图片和相关的文本分配给特定的地理位置。例如,上面的地图实例首先新建了张飞、刘备和关羽的OverlayItem,然后将OverlayItem添加到ItemizedOverlay中,最后将这组标注点呈现在地图上。

1.4. 玄德有话说

张飞:地图一片空白怎么办

刘备:首先查看网络是否正常,然后检查apikey是否无效,最后刷新。

 

张飞:Overlay和图层有啥关系?

刘备:一个图像的显示可以有多个图层相互叠加在一起,上面图层的涂画不会影响到下面的图层。通过移动各层的相对位置或者添加更多的图层形成最后的合成效果。而每一个Overlay都是一块具有透明背景的画布,地图服务中把它作为一个图层覆盖在地图上方,对地图进行扩展。

0 0
原创粉丝点击