概述
基于位置的服务已经深入到了我们生活中的每一个角落,这些服务我们统称为LBS(Location Based Service),我们常见的App(淘宝、QQ、微信、美团、大众点评、百度糯米、饿了么等)都内置了地图定位服务。在我们以后的程序员生涯中难免要和LBS打交道。
国内提供地图服务的公司主要有百度地图、高德地图、腾讯地图、搜狗地图。其中百度地图从用户数量和服务质量上都处于领先地位,高德地图紧随其后,这里我们以百度地图为例来演示如何使用第三方定位服务。
百度地图移动版API(Android)是一套基于Android设备的应用程序接口,通过该接口,可以轻松访问百度服务和数据,构建功能丰富、交互性强的地图应用程序。百度地图不仅包含构建地图的基本接口,还提供了本地搜索、路线规划、地图定位等数据服务。
这篇文章使用的是百度地图在2015年6月18日发布了Android SDK v3.5.0版本。
如今百度地图已经将定位功能,单独剥离出来了,因此在这篇文章中我们还要讨论的第二个重要内容就是百度定位SDK的使用。
百度于2015年7月17日发布了百度定位Android SDK v6.0.3产品,该产品也是本文章所使用的版本。
百度地图功能
百度地图 Android SDK 是一套基于Android 2.1 及以上版本设备的应用程序接口, 您可以通过该接口实现丰富的LBS 功能:
- 地图:提供地图(2D、3D)的展示和缩放、平移、旋转、改变视角等地图操作
- POI 检索:可根据关键字,对POI 数据进行周边、区域和城市内三种检索
- 地理编码:提供地理坐标和地址之间相互转换的能力
- 线路规划:支持公交信息查询、公交换乘查询、驾车线路规划和步行路径检索
- 覆盖物:提供多种地图覆盖物(自定义标注、几何图形、文字绘制、地形图图层、热力图图层等),满足开发者的各种需求
- 定位:采用多种定位模式,使用定位SDK 获取位置信息,使用地图SDK 我的位置图层进行位置展示
- 离线地图:支持使用离线地图,节省用户流量,同时为用户带来更好的地图体验
- 调启百度地图:利用SDK 接口,直接在本地打开百度地图客户端或WebApp,实现地图功能
- 周边雷达:利用周边雷达功能,开发者可在App 内低成本、快速实现查找周边使用相同App 的用户位置的功能
- LBS 云检索:支持用户检索存储在LBS 云内的自有POI 数据,并展示
- 瓦片图层:支持开发者在地图上添加自有瓦片数据
- 特色功能:提供短串分享、Place 详情检索、热力图等特色功能,帮助开发者搭建功能更加强大的应用
什么是百度地图API
百度地图移动版API(Android)是一套基于Android设备的应用程序接口,通过该接口,可以轻松访问百度服务和数据,构建功能丰富、交互性强的地图应用程序。
百度地图移动版API不仅包含构建地图的基本接口,还提供了本地搜索、路线规划、地图定位等数据服务。
百度地图入门
定位需要的相关权限
<!-- 这个权限用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
<!-- 这个权限用于访问GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
<!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<!-- 获取运营商信息,用于支持提供运营商信息相关的接口-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
<!-- 用于读取手机当前的状态-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
<!-- 写入扩展存储,向扩展卡写入数据,用于写入离线定位数据-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<!-- 访问网络,网络定位需要上网-->
<uses-permission android:name="android.permission.INTERNET" />
<!-- SD卡读取权限,用户写入离线定位数据-->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"></uses-permission>
<!--允许应用读取低级别的系统日志文件 -->
<uses-permission android:name="android.permission.READ_LOGS"></uses-permission>
准备工作
获取API Key
地址:http://developer.baidu.com/map/android-mobile-apply-key.htm
建立工程
添加地图引擎到Andoid工程中
- 添加jar包: baidumapapi_v3_3_0.jar和locSDK_5.0.jar
- 添加.so文件:拷贝libBaiduMapSDK_v3_3_0_15.so 、 liblocSDK5.so到libs\armeabi目录下
- 注: locSDK_5.0.jar和liblocSDK5.so为百度定位SDK所使用资源,开发者可根据实际需求自行添加。
添加权限
初始化地图引擎
引入布局(地图控件)
Hellworld
布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.baidu.mapapi.map.MapView
android:id="@+id/mapview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
public class Hellworld extends Activity {
private MapView mMapView;
private BaiduMap baiduMap;
private BroadcastReceiver receiver;
double latitude = 22.582387;//纬度
double longitude = 113.927331;//经度
LatLng mLatLng = new LatLng(latitude, longitude);//经纬度
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initSDK();
setContentView(R.layout.activity_main);
initBaiduMap();
}
private void initBaiduMap() {
mMapView = (MapView) findViewById(R.id.mapview);
baiduMap = mMapView.getMap();
baiduMap.setMapStatus(MapStatusUpdateFactory.zoomTo(17));
baiduMap.setMapStatus(MapStatusUpdateFactory.newLatLng(mLatLng));
}
private void initSDK() {
SDKInitializer.initialize(getApplicationContext());
IntentFilter filter = new IntentFilter();
filter.addAction(SDKInitializer.SDK_BROADCAST_ACTION_STRING_NETWORK_ERROR);
filter.addAction(SDKInitializer.SDK_BROADTCAST_ACTION_STRING_PERMISSION_CHECK_ERROR);
receiver = new MyRecevier();
registerReceiver(receiver, filter);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_1: //放大一个级别
MapStatusUpdate zoomInUpdate = MapStatusUpdateFactory.zoomIn();
baiduMap.setMapStatus(zoomInUpdate );
break;
case KeyEvent.KEYCODE_2: //缩小一个级别
MapStatusUpdate zoomOutUpdate = MapStatusUpdateFactory.zoomOut();
baiduMap.setMapStatus(zoomOutUpdate );
break;
case KeyEvent.KEYCODE_3: //以一个点为中心旋转 0~360°
MapStatus mapStatu = baiduMap.getMapStatus();
float rotate = mapStatu.rotate;
MapStatus rotateStatus = new MapStatus.Builder().rotate(rotate+30).build();
MapStatusUpdate rotateUpdate = MapStatusUpdateFactory.newMapStatus(rotateStatus );
baiduMap.setMapStatus(rotateUpdate );
break;
case KeyEvent.KEYCODE_4: //俯角 overlook -45-0 以一条直线为轴
MapStatus oldStatu = baiduMap.getMapStatus();
float overlook = oldStatu.overlook;
MapStatus overlookStatus = new MapStatus.Builder().overlook(overlook-5).build();
MapStatusUpdate overlookUpdate = MapStatusUpdateFactory.newMapStatus(overlookStatus );
baiduMap.setMapStatus(overlookUpdate );
break;
default:
break;
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
mMapView.onDestroy();
unregisterReceiver(receiver);
}
@Override
protected void onResume() {
super.onResume();
// 在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理
mMapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
// 在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理
mMapView.onPause();
}
class MyRecevier extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (SDKInitializer.SDK_BROADCAST_ACTION_STRING_NETWORK_ERROR.equals(action)) {
Toast.makeText(getApplicationContext(), "网络错误", Toast.LENGTH_LONG).show();
} else if (SDKInitializer.SDK_BROADTCAST_ACTION_STRING_PERMISSION_CHECK_ERROR.equals(action)) {
Toast.makeText(getApplicationContext(), "校验失败", Toast.LENGTH_LONG).show();
}
}
}
}
地图图层
什么是地图图层
地图可以包含一个或多个图层,每个图层在每个级别都是由若干个图块组成的,它们覆盖了地图的整个表面。例如您所看到包括街道、兴趣点、学校、公园等内容的地图展现就是一个图层,另外交通流量的展现也是通过图层来实现的。
图层分类
底图
基本的地图图层,包括若干个缩放级别,显示基本的地图信息,包括道路、街道、学校、公园等内容。
实时交通信息图
baiduMap.setTrafficEnabled(true);
卫星图
baiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE);
卫星地图是卫星拍摄的真实的地理面貌,所以卫星地图可用来检测地面的信息,你可以了解到地理位置,地形等。
百度地图SDK为广大开发者提供的基础地图和上面的各种覆盖物元素,具有一定的层级压盖关系,具体如下(从下至上的顺序)
1、基础底图(包括底图、底图道路、卫星图等)
2、地形图图层(GroundOverlay)
3、热力图图层(HeatMap)
4、实时路况图图层(BaiduMap.setTrafficEnabled(true);)
5、百度城市热力图(BaiduMap.setBaiduHeatMapEnabled(true);)
6、底图标注(指的是底图上面自带的那些POI元素)
7、几何图形图层(点、折线、弧线、圆、多边形)
8、标注图层(Marker),文字绘制图层(Text)
9、指南针图层(当地图发生旋转和视角变化时,默认出现在左上角的指南针)
10、定位图层(BaiduMap.setMyLocationEnabled(true);)
11、弹出窗图层(InfoWindow)
12、自定义View(MapView.addView(View);)
BaseMapActivity
public class BaseMapActivity extends Activity {
protected MapView mMapView;
protected BaiduMap baiduMap;
protected double latitude = 22.582387;//纬度
protected double longitude = 113.927331;//经度
protected LatLng hmPos = new LatLng(latitude, longitude);//经纬度
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.common);
initBaiduMap();
}
private void initBaiduMap() {
mMapView = (MapView) findViewById(R.id.mapview);
baiduMap = mMapView.getMap();
baiduMap.setMapStatus(MapStatusUpdateFactory.zoomTo(17));
baiduMap.setMapStatus(MapStatusUpdateFactory.newLatLng(hmPos));
}
void showToast(String msg){
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
}
}
LayerDemo
public class LayerDemo extends BaseMapActivity {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_1: //普通地图
baiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
baiduMap.setTrafficEnabled(false);
break;
case KeyEvent.KEYCODE_2://卫星图
baiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE);
baiduMap.setTrafficEnabled(false);
break;
case KeyEvent.KEYCODE_3://实时交通图
baiduMap.setTrafficEnabled(true);
break;
default:
break;
}
return super.onKeyDown(keyCode, event);
}
}
覆盖物
所有叠加或覆盖到地图的内容,我们统称为地图覆盖物。如标注、矢量图形元素(包括:折线和多边形和圆)、定位图标等。覆盖物拥有自己的地理坐标,当您拖动或缩放地图时,它们会相应的处理。
本地覆盖物
- 本地覆盖物的抽象基类:OverlayOptions(核心类)
- 圆形覆盖物: CircleOptions
- 文字覆盖物: TextOptions
- 标注覆盖物: MarkerOptions
- 圆点覆盖物:DotOptions
- 地形覆盖物:GroundOverlayOptions
- 圆点覆盖物:DotOptions
- 多边形覆盖物:PolygonOptions
- 折线覆盖物:PolylineOptions
- 弧线覆盖物:ArcOptions
baiduMap.addOverlay(ooCircle);//添加覆盖物
搜索覆盖物
- 搜索覆盖物抽象类: OverlayManager (核心类)
- 本地搜索覆盖物:PoiOverlay
- 驾车路线覆盖物:DrivingRouteOverlay
- 步行路线覆盖物:WalkingRouteOverlay
- 换乘路线覆盖物:TransitOverlay
- 公交路线覆盖物:BusLineOverlay
//添加覆盖物
overlay.setData(result);
overlay.addToMap();
overlay.zoomToSpan();
圆形覆盖物CircleOptions
绘制步骤
- 创建圆形: CircleOptions()
- 设置圆心坐标:center(LatLng center)
- 设置圆填充颜色:fillColor(int color) ,16进制如:#00ff0000 透明、红、绿、蓝
- 设置圆半径:radius(int radius)
- 设置圆边框信息:stroke(Stroke stroke)
- 设置圆是否可见:visible(boolean visible)
- 设置圆zIndex(显示优先级)信息:zIndex(int zIndex),值越大优先级越高
public class CircleOptionsDemo extends BaseMapActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
draw();
}
private void draw() {
CircleOptions circle = new CircleOptions()
.center(hmPos)//定义圆心
.fillColor(0x60FF0000)//定义填充颜色
.radius(1000)//定义半径
.stroke(new Stroke(10, Color.BLUE)); //边框,参数:宽度、颜色
baiduMap.addOverlay(circle);
}
}
文本覆盖物TextOptions
绘制步骤
- 创建文字覆盖物对象, TextOptions()
- 设置文字覆盖物地理坐标:position(LatLng position)
- 设置文字覆盖物旋转角度,逆时针:rotate(float rotate)
- 设置文字覆盖物的文字内容:text(java.lang.String text)
- 设置文字覆盖物字体:typeface(Typeface typeface)
- 设置文字覆盖物可见性:visible(boolean visible)
- 设置文字覆盖物 zIndex:zIndex(int zIndex)
- 设置文字覆盖物对齐方式,默认居中对齐:align(int alignX, int alignY)
- 设置文字覆盖物背景颜色:bgColor(int bgColor)
- 设置文字覆盖物额外信息:extraInfo(Bundle extraInfo)
- 设置文字覆盖物字体颜色,默认黑色:fontColor(int color)
- 设置文字覆盖物字体大小:fontSize(int size)
public class TextOptionsDemo extends BaseMapActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
draw();
}
private void draw() {
TextOptions options = new TextOptions()
.position(hmPos)
.bgColor(Color.BLACK)
.fontColor(Color.BLUE)
.fontSize(12)
.typeface(Typeface.SERIF)
.text("鹏程深圳");
baiduMap.addOverlay(options);
}
}
标注覆盖物MarkerOptions
某个类型的覆盖物,包含多个类型相同、显示方式相同、处理方式相同的项时,使用此类。或者用来标记位置。
开发步骤
- 设置 marker 覆盖物的位置坐标:position(LatLng position)
- 设置 marker 覆盖物的标题:title(java.lang.String title)
- 设置 Marker 覆盖物的图标:icon(BitmapDescriptor icon)
- 设置 marker 是否允许拖拽,默认不可拖拽:draggable(boolean draggable)
public class MarkerOptionsDemo extends BaseMapActivity {
private View pop;
private TextView titleText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initPop();
draw();
}
private void initPop() {
pop = View.inflate(this, R.layout.pop, null);
//必须MapViewLayoutParams
LayoutParams params = new MapViewLayoutParams.Builder()
.height(MapViewLayoutParams.WRAP_CONTENT)
.width(MapViewLayoutParams.WRAP_CONTENT)
.layoutMode(ELayoutMode.mapMode)//使用经纬度的方式设置控件的位置
.position(hmPos)
.yOffset(-5)
.build();
pop.setVisibility(View.GONE);
titleText = (TextView) pop.findViewById(R.id.title);
mMapView.addView(pop, params);
}
private void draw() {
MarkerOptions markerOptions = new MarkerOptions();
BitmapDescriptor icon = BitmapDescriptorFactory.fromResource(R.drawable.eat_icon);
ArrayList<BitmapDescriptor> icons = new ArrayList<BitmapDescriptor>();
icons.add(icon);
icons.add(BitmapDescriptorFactory.fromResource(R.drawable.icon_geo));
markerOptions.draggable(true).icons(icons).title("世界之窗").position(hmPos).period(10);
baiduMap.addOverlay(markerOptions);
markerOptions = new MarkerOptions().title("向北").position(new LatLng(latitude + 0.001,
longitude)).icon(icon);
baiduMap.addOverlay(markerOptions);
markerOptions = new MarkerOptions().title("向东").position(new LatLng(latitude, longitude +
0.001)).icon(icon);
baiduMap.addOverlay(markerOptions);
markerOptions = new MarkerOptions().title("向西南").position(new LatLng(latitude - 0.001,
longitude - 0.001)).icon(icon);
baiduMap.addOverlay(markerOptions);
baiduMap.setOnMarkerClickListener(new OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker) {
String title = marker.getTitle(); //设置title
titleText.setText(title);
LayoutParams params = new MapViewLayoutParams.Builder()
.height(MapViewLayoutParams.WRAP_CONTENT)
.width(MapViewLayoutParams.WRAP_CONTENT)
.layoutMode(ELayoutMode.mapMode)
.position(marker.getPosition())
.yOffset(-5)
.build();
//更新pop的位置并显示出来
mMapView.updateViewLayout(pop, params);
pop.setVisibility(View.VISIBLE);
return false;
}
});
}
}
搜索
百度地图移动版API集成搜索服务包括
位置检索、周边检索、范围检索、公交检索、驾乘检索、步行检索
核心类:
- PoiSearch和OnGetPoiSearchResultListener
- RoutePlanSearch和OnGetRoutePlanResultListener
实现思路
- 初始化PoiSearch类,通过setOnGetPoiSearchResultListener方法注册搜索结果的监听对象OnGetPoiSearchResultListener ,实现异步搜索服务。
- 通过自定义MySearchListener实现类,处理不同的回调方法,获得搜索结果。
- 注意, OnGetPoiSearchResultListener只支持一个,以最后一次设置为准
结合覆盖物展示搜索
- 本地搜索覆盖物:PoiOverlay
- 驾车路线覆盖物:DrivingRouteOverlay
- 步行路线覆盖物:WalkingRouteOverlay
- 换乘路线覆盖物:TransitOverlay
本地搜索
POI(Point of Interest兴趣点)搜索有三种方式
- PoiSearch.searchInBound() 范围搜索
- PoiSearch.searchNearby() 周边搜索
- PoiSearch.searchInCity() 全城搜索
- PoiSearch.searchPoiDetail() 详细信息检索
根据范围和检索词发起范围检索
public class PoiSearchInboundsDemo extends BaseMapActivity {
private PoiSearch poiSearch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
search();
}
private void search() {
poiSearch = PoiSearch.newInstance();
LatLngBounds bounds = new LatLngBounds.Builder()
.include(new LatLng(22.561179, 113.895532)) //左下点的经纬度
.include(new LatLng(22.602357, 113.952448))
.build();
PoiBoundSearchOption inBoundSearchOption = new PoiBoundSearchOption()
.keyword("酒店")
.bound(bounds);
poiSearch.setOnGetPoiSearchResultListener(new OnGetPoiSearchResultListener() {
@Override
public void onGetPoiResult(PoiResult result) {
if (result.error == SearchResult.ERRORNO.NO_ERROR) {
PoiOverlay poiOverlay = new MyPoiOverlay(baiduMap);
baiduMap.setOnMarkerClickListener(poiOverlay);
poiOverlay.setData(result); //设置数据
poiOverlay.addToMap();//添加到地图
poiOverlay.zoomToSpan();//缩放到合适视野范围
} else {
showToast("为搜索到内容");
}
}
@Override
public void onGetPoiDetailResult(PoiDetailResult result) {
}
});
poiSearch.searchInBound(inBoundSearchOption);
}
//结果展示
class MyPoiOverlay extends PoiOverlay {
public MyPoiOverlay(BaiduMap map) {
super(map);
}
@Override
public boolean onPoiClick(int position) {
PoiResult poiResult = getPoiResult(); //获取到setData时的搜索结果
List<PoiInfo> allPoi = poiResult.getAllPoi();
PoiInfo poiInfo = allPoi.get(position); //根据点击的位置获取到poi信息
showToast("name: " + poiInfo.name + ", address: " + poiInfo.address);
return super.onPoiClick(position);
}
}
}
周边检索
public class PoiSearchNearByDemo extends BaseMapActivity {
private PoiSearch poiSearch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
search();
}
private void search() {
poiSearch = PoiSearch.newInstance();
poiSearch.setOnGetPoiSearchResultListener(new OnGetPoiSearchResultListener() {
@Override
public void onGetPoiResult(PoiResult result) {
if (result.error == SearchResult.ERRORNO.NO_ERROR) {
PoiOverlay poiOverlay = new MyPoiOverlay(baiduMap);
baiduMap.setOnMarkerClickListener(poiOverlay);
poiOverlay.setData(result); // 设置数据
poiOverlay.addToMap(); // 添加到地图
poiOverlay.zoomToSpan(); // 缩放到合适视野范围
} else {
showToast("未搜索到内容");
}
}
@Override
public void onGetPoiDetailResult(PoiDetailResult result) {
if (result.error == SearchResult.ERRORNO.NO_ERROR) {
showToast("name:" + result.getName()
+ "env: " + result.getEnvironmentRating()
+ "price: " + result.getPrice());
} else {
showToast("未搜索到详细内容");
}
}
});
PoiNearbySearchOption nearByOption = new PoiNearbySearchOption()
.location(hmPos)
.radius(3000)
.keyword("酒店");
poiSearch.searchNearby(nearByOption);
}
class MyPoiOverlay extends PoiOverlay {
public MyPoiOverlay(BaiduMap map) {
super(map);
}
@Override
public boolean onPoiClick(int position) {
PoiResult poiResult = getPoiResult(); // 获取到setData时的搜索结果
List<PoiInfo> allPoi = poiResult.getAllPoi();
PoiInfo poiInfo = allPoi.get(position); // 根据点击的位置获取到poi信息
PoiDetailSearchOption detailOption = new PoiDetailSearchOption();
detailOption.poiUid(poiInfo.uid);
// showToast("name: "+poiInfo.name+", address: "+poiInfo.address);
poiSearch.searchPoiDetail(detailOption);
return super.onPoiClick(position);
}
}
}
全城搜索
public class PoiSearchCityDemo extends BaseMapActivity {
private PoiSearch poiSearch;
private int curreantNum;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
search();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_1:
curreantNum++;
search();
break;
default:
break;
}
return super.onKeyDown(keyCode, event);
}
private void search() {
poiSearch = PoiSearch.newInstance();
poiSearch.setOnGetPoiSearchResultListener(new OnGetPoiSearchResultListener() {
private PoiOverlay poiOverlay;
@Override
public void onGetPoiResult(PoiResult result) {
if (result.error == SearchResult.ERRORNO.NO_ERROR) {
showToast("总共:" + result.getTotalPageNum()
+ "页,当前是第" + result.getCurrentPageNum() +
"页,第几条:" + result.getCurrentPageCapacity());
// if(poiOverlay != null){
// poiOverlay.removeFromMap();
// }
baiduMap.clear();
poiOverlay = new MyPoiOverlay(baiduMap);
baiduMap.setOnMarkerClickListener(poiOverlay);
poiOverlay.setData(result); // 设置数据
poiOverlay.addToMap(); // 添加到地图
poiOverlay.zoomToSpan(); // 缩放到合适视野范围
} else {
showToast("未搜索到内容");
}
}
@Override
public void onGetPoiDetailResult(PoiDetailResult result) {
if (result.error == SearchResult.ERRORNO.NO_ERROR) {
showToast("name:" + result.getName()
+ "env: " + result.getEnvironmentRating()
+ "price: " + result.getPrice());
} else {
showToast("未搜索到详细内容");
}
}
});
PoiCitySearchOption cityOption = new PoiCitySearchOption()
.city("深圳").keyword("酒店")
.pageNum(curreantNum)
.pageCapacity(15);
poiSearch.searchInCity(cityOption);
}
class MyPoiOverlay extends PoiOverlay {
public MyPoiOverlay(BaiduMap map) {
super(map);
}
@Override
public boolean onPoiClick(int position) {
PoiResult poiResult = getPoiResult(); // 获取到setData时的搜索结果
List<PoiInfo> allPoi = poiResult.getAllPoi();
PoiInfo poiInfo = allPoi.get(position); // 根据点击的位置获取到poi信息
PoiDetailSearchOption detailOption = new PoiDetailSearchOption();
detailOption.poiUid(poiInfo.uid);
// showToast("name: "+poiInfo.name+", address: "+poiInfo.address);
poiSearch.searchPoiDetail(detailOption);
return super.onPoiClick(position);
}
}
}
查询加油站信息
多种查询方法,但结果的处理都在OnGetPoiSearchResultListener的onGetPoiResult方法中
处理步骤:
- 判断服务器结果返回
- 创建poi覆盖物
- 将服务器返回数据添加到poi覆盖物中
- 添加覆盖物到地图addToMap
- 缩放地图,使所有Overlay都在合适的视野内
注意
- POI检索结果每页容量默认情况下为10,可以通过pageCapacity设置,支持1-50(10)
- 翻页功能重新调用通过PoiSearch类的searchInXxx()方法并传递页数角标pageNum来实现,该方法是异步函数,搜索成功后会调用注册的事件处理函数onGetPoiResult 返回查询页的结果。
路线规划
1、驾车路线
结果展示: DrivingRouteOverlay
案例:从黑马到传智路线查询
- 查询:RoutePlanSearch.drivingSearch()驾乘路线搜索,或者增加途经点.
- PlanNode内容的设置:可以使用经纬度和地名,但不支持模糊查询,需要输入准确的名称
- 可以通过DrivingRoutePlanOption.policy (int policy) 来设置驾车路线规划策略
- 结果处理:OnGetRoutePlanResultListener. onGetDrivingRouteResult(DrivingRouteResult result)
public class DrivingRouteDemo extends BaseMapActivity {
private RoutePlanSearch routeSearch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
search();
}
private void search() {
routeSearch = RoutePlanSearch.newInstance();
ArrayList<PlanNode> pass = new ArrayList<PlanNode>();
pass.add(PlanNode.withCityNameAndPlaceName("深圳", "塘朗山公园"));
DrivingRoutePlanOption drivingOption = new DrivingRoutePlanOption()
.from(PlanNode.withLocation(hmPos))//出发点
.to(PlanNode.withLocation(new LatLng(22.617616, 114.036116)))//终点
.passBy(pass)
.policy(DrivingPolicy.ECAR_TIME_FIRST);//出行策略,费用低或者时间短、距离近等
routeSearch.setOnGetRoutePlanResultListener(new OnGetRoutePlanResultListener() {
@Override
public void onGetWalkingRouteResult(WalkingRouteResult result) {
}
@Override
public void onGetTransitRouteResult(TransitRouteResult result) {
}
@Override
public void onGetDrivingRouteResult(DrivingRouteResult result) {
if (result.error == SearchResult.ERRORNO.NO_ERROR) {
DrivingRouteOverlay drivingRouteOverlay = new DrivingRouteOverlay(baiduMap)
.setData(result.getRouteLines().get(0))//设置第一条线路
.addToMap()
.zoomToSpan();
} else {
showToast("未搜索到相关路线");
}
}
});
routeSearch.drivingSearch(drivingOption);
}
}
2、步行路线
结果展示: WalkingRouteOverlay
RoutePlanSearch. walkingSearch()步行路线搜索
结果处理: OnGetRoutePlanResultListener. onGetWalkingRouteResult(WalkingRouteResult result)
public class WalkingRouteDemo extends BaseMapActivity {
private RoutePlanSearch routeSearch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
search();
}
private void search() {
routeSearch = RoutePlanSearch.newInstance();
// ArrayList<PlanNode> pass = new ArrayList<PlanNode>();
// pass.add(PlanNode.withCityNameAndPlaceName("深圳", "塘朗山公园"));
routeSearch.setOnGetRoutePlanResultListener(new OnGetRoutePlanResultListener() {
@Override
public void onGetWalkingRouteResult(WalkingRouteResult result) {
if (result.error == SearchResult.ERRORNO.NO_ERROR) {
WalkingRouteOverlay walkingRouteOverlay = new MyWalkingOverlay(baiduMap)
.setData(result.getRouteLines().get(0))
.addToMap()
.zoomToSpan();
} else {
showToast("未搜索到相关路线");
}
}
@Override
public void onGetTransitRouteResult(TransitRouteResult result) {
}
@Override
public void onGetDrivingRouteResult(DrivingRouteResult result) {
}
});
WalkingRoutePlanOption walkingOption = new WalkingRoutePlanOption()
.from(PlanNode.withLocation(hmPos))
.to(PlanNode.withCityNameAndPlaceName("深圳", "灵芝地铁站"));
routeSearch.walkingSearch(walkingOption);
}
class MyWalkingOverlay extends WalkingRouteOverlay {
public MyWalkingOverlay(BaiduMap arg0) {
super(arg0);
}
@Override
public BitmapDescriptor getStartMarker() {
return BitmapDescriptorFactory.fromResource(R.drawable.icon_st);
}
@Override
public BitmapDescriptor getTerminalMarker() {
return BitmapDescriptorFactory.fromResource(R.drawable.icon_en);
}
}
}
3、换乘路线
结果展示:TransitRouteOverlay
检索: RoutePlanSearch. transitSearch()
通过TransitRoutePlanOption.policy (int policy) 设置路线规划策略
结果处理: OnGetRoutePlanResultListener. onGetTransitRouteResult(TransitRouteResult result)
public class TransitRouteDemo extends BaseMapActivity {
private RoutePlanSearch routeSearch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
search();
}
private void search() {
routeSearch = RoutePlanSearch.newInstance();
// ArrayList<PlanNode> pass = new ArrayList<PlanNode>();
// pass.add(PlanNode.withCityNameAndPlaceName("深圳", "塘朗山公园"));
routeSearch.setOnGetRoutePlanResultListener(new OnGetRoutePlanResultListener() {
@Override
public void onGetWalkingRouteResult(WalkingRouteResult result) {
}
@Override
public void onGetTransitRouteResult(TransitRouteResult result) {
if (result.error == SearchResult.ERRORNO.NO_ERROR) {
TransitRouteOverlay transitRouteOverlay = new TransitRouteOverlay(baiduMap)
.setData(result.getRouteLines().get(0))
.addToMap()
.zoomToSpan();
} else {
showToast("未搜索到相关路线");
}
}
@Override
public void onGetDrivingRouteResult(DrivingRouteResult result) {
}
});
TransitRoutePlanOption transitOption = new TransitRoutePlanOption()
.city("深圳")
.from(PlanNode.withLocation(hmPos)) //22.617616,114.036116
.to(PlanNode.withLocation(new LatLng(22.617616, 114.036116)))
.policy(TransitPolicy.EBUS_NO_SUBWAY);
routeSearch.transitSearch(transitOption);
}
}
地址解析服务
GeoCoder.geocode(GeoCodeOption option)
根据地址名获取地址信息 异步函数,返回结果在OnGetGeoCoderResultListener里的onGetGeoCodeResult()方法通知
GeoCoder.reverseGeoCode(ReverseGeoCodeOption option)
根据地理坐标点获取地址信息 异步函数,返回结果在OnGetGeoCoderResultListener里的onGetReverseGeoCodeResult()方法通知
联想词检索
SuggestionSearch . requestSuggestion(SuggestionSearchOption option)
查询一系列与指定key相关的内容,结果中包括城市及包含key的名称
结果处理OnGetSuggestionResultListener . onGetSuggestionResult(SuggestionResult result)
公交路线详细信息搜索
检索: BusLineSearch. searchBusLine(BusLineSearchOption option)
busLineUid()信息获取:公交线路的uid,可以通过poi查询返回的结果中获取MKPoiInfo的uid。
使用poiSearchInCity查询公交线信息,利用PoiInfo的type可以判断poi类型,当类型为公交线路时,记录当前的PoiInfo中的uid信息。
利用获取的uid信息进行公交线的查询
结果处理:在OnGetBusLineSearchResultListener. onGetBusLineResult(BusLineResult result)中进行结果的处理,此时使用到的覆盖物是BusLineOverlay
0:普通点
1:公交站
2:公交线路
3:地铁站
4:地铁线路
定位
在百度地图移动版API中,提供一个重要的特色功能:定位,通过这个功能,能获取到用户当前所在位置。
在程序中,如果使用此功能,必须注册GPS和网络的使用权限。
在获取用户位置时,优先使用GPS进行定位;如果GPS定位没有打开或者没有可用位置信息,则会通过判断网络是否连接(即确认手机是否能上网,不论是连接2G/3G或Wi-Fi网络),如果是,则通过请求百度网络定位服务,返回网络定位结果。为了使获得的网络定位结果更加精确,请打开手机的Wi-Fi开关。
目前系统自带的网络定位服务精度低,且服务不稳定、精度低,并且从未来的趋势看,基站定位是不可控的(移动公司随时可能更改基站编号以垄断定位服务),而Wi-Fi定位则不然,它是一种精度更高、不受管制的定位方法。国内其它使用Wi-Fi定位的地图软件,Wi-Fi定位基本不可用,百度的定位服务量化指标优秀,网络接口返回速度快(服务端每次定位响应时间50毫秒以内),平均精度70米,其中Wi-Fi精度40米左右,基站定位精度200米左右,覆盖率98%,在国内处于一枝独秀的地位。
注意
关于经纬度的说明:该经纬度信息是经过加密处理,所以在其它地图工具中测得的经纬度 信息不适合百度的坐标系统。
使用百度经纬度坐标,可以通过http://api.map.baidu.com/lbsapi/getpoint/index.html查询地理坐标如果需要在百度地图上显示使用其他坐标系统的位置,请发邮件至mapapi@baidu.com申请坐标转换接口
LocationClient和BDLocationListener
首先需要打开定位图层BaiduMap.setMyLocationEnabled(true);
设置监听器LocationClient. registerLocationListener(BDLocationListener)
设置定位模式baiduMap. setLocationMode(LocationMode)
Hight_Accuracy,高精度定位模式:这种定位模式下,会同时使用网络定位和GPS定位,优先返回最高精度的定位结果;
Battery_Saving,低功耗定位模式:这种定位模式下,不会使用GPS,只会使用网络定位(Wi-Fi和基站定位)
Device_Sensors,仅用设备定位模式:这种定位模式下,不需要连接网络,只使用GPS进行定位,这种模式下不支持室内环境的定位
设置定位显示模式BaiduMap.setMyLocationConfigeration(MyLocationConfiguration)
定位数据获取:在BDLocationListener. onReceiveLocation(BDLocation result)方法中设置定位数据,
baiduMap.setMyLocationData(MyLocationData);
百度定位
public class LocationDemo extends BaseMapActivity {
public LocationClient mLocationClient;
public BDLocationListener myListener;
private BitmapDescriptor geo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
lacate();
}
private void lacate() {
mLocationClient = new LocationClient(getApplicationContext());
myListener = new MyListener();
mLocationClient.registerLocationListener(myListener);
LocationClientOption option = new LocationClientOption()
.setLocationMode(LocationMode.Hight_Accuracy)//设置定位模式
.setCoorType("bd09ll")// 返回的定位结果是百度经纬度,默认值gcj02
.setScanSpan(5000)// 设置发起定位请求的间隔时间为5000ms
.setIsNeedAddress(true)// 返回的定位结果包含地址信息
.setNeedDeviceDirect(true);// 返回的定位结果包含手机机头的方向
mLocationClient.setLocOption(option);
geo = BitmapDescriptorFactory.fromResource(R.drawable.icon_geo);
MyLocationConfiguration configuration = new MyLocationConfiguration(
MyLocationConfiguration.LocationMode.FOLLOWING, true, geo);
baiduMap.setMyLocationConfigeration(configuration);// 设置定位显示的模式
baiduMap.setMyLocationEnabled(true);// 打开定位图层
}
@Override
protected void onStart() {
mLocationClient.start();
super.onStart();
}
@Override
protected void onPause() {
mLocationClient.stop();
super.onPause();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_1:// 正常
// 设置定位显示的模式
baiduMap.setMyLocationConfigeration(new MyLocationConfiguration(
MyLocationConfiguration.LocationMode.NORMAL, true, geo));
break;
case KeyEvent.KEYCODE_2:// 罗盘
// 设置定位显示的模式
baiduMap.setMyLocationConfigeration(new MyLocationConfiguration(
MyLocationConfiguration.LocationMode.COMPASS, true, geo));
break;
case KeyEvent.KEYCODE_3:// 跟随
// 设置定位显示的模式
baiduMap.setMyLocationConfigeration(new MyLocationConfiguration(
MyLocationConfiguration.LocationMode.FOLLOWING, true, geo));
break;
default:
break;
}
return super.onKeyDown(keyCode, event);
}
class MyListener implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation result) {
if (result != null) {
MyLocationData data = new MyLocationData.Builder()
.latitude(result.getLatitude())
.longitude(result.getLongitude()).build();
baiduMap.setMyLocationData(data);
}
}
}
}
位置分享
public class ShareUrlSearchDemo extends Activity {
private ShareUrlSearch mShareUrlSearch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mShareUrlSearch = ShareUrlSearch.newInstance();
mShareUrlSearch.setOnGetShareUrlResultListener(shareUrlResultListener);
LocationShareURLOption locationShareURLOption = new LocationShareURLOption()
.location(mCurrentMarker.getPosition())
.name("我的位置")
.snippet("这是我的位置");
mShareUrlSearch.requestLocationShareUrl(locationShareURLOption);
}
private OnGetShareUrlResultListener shareUrlResultListener = new OnGetShareUrlResultListener() {
public void onGetPoiDetailShareUrlResult(ShareUrlResult result) {
//分享POI详情
}
public void onGetLocationShareUrlResult(ShareUrlResult result) {
//分享位置信息
String url = result.getUrl();
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, url);
sendIntent.setType("text/plain");//
startActivity(Intent.createChooser(sendIntent, "位置分享"));
}
};
}
离线地图
/** 离线地图初始化 **/
mOffline = new MKOfflineMap();
mOffline.init(mBMapMan, new MKOfflineMapListener() {
public void onGetOfflineMapState(int type, int state) {
switch (type) {
case MKOfflineMap.TYPE_DOWNLOAD_UPDATE:
{
MKOLUpdateElement update = mOffline.getUpdateInfo(state);
//mText.setText(String.format("%s : %d%%", update.cityName, update.ratio));
}
break;
case MKOfflineMap.TYPE_NEW_OFFLINE:
Log.d("OfflineDemo", String.format("add offlinemap num:%d", state));
break;
case MKOfflineMap.TYPE_VER_UPDATE:
Log.d("OfflineDemo", String.format("new offlinemap ver"));
break;
}
}
}
);
/** 离线地图导入离线包 **/
int num = mOffline.scan();
这篇博客介绍了如何在Android应用中使用百度地图API进行地图开发,包括地图图层、覆盖物、搜索、路线规划和定位等功能。通过实例展示了添加相关权限、获取API Key、初始化地图引擎以及使用定位SDK的步骤,还涵盖了百度地图的不同图层类型、覆盖物的绘制,以及搜索和路线规划的实现。

3092

被折叠的 条评论
为什么被折叠?



