准备工作
申请api
申请百度地图的api,得到AKkey:BGOOsAkMsvNkgUGmWajLgEIQgtthsnwX
在AndroidManifest.xml文件下的application
标签下加上
在项目中集成BaiduMapSDK
添加jar文件
切换到Project
视图,在app
目录下的libs
目录下,将BaiduLBS_Android.jar
放置其中。
添加so文件
仍然在libs
目录下,将其他文件一同拷入。在app
目录下的build.gradle
文件中的android
模块中配置sourceSets
标签,详细代码如下:
sourceSets {
main {
jniLibs.srcDir 'libs'
}
}
往工程添加jar文件
在libs
目录下,选中每一个jar文件,右键,选择Add As Library...
应用混淆
编写混淆文件,打开app
目录下的proguard-rules.pro
文件,添加如下代码:
-keep class com.baidu.** {*;}
-keep class mapsdkvi.com.** {*;}
-dontwarn com.baidu.**
显示地图
配置AndroidManifest文件
在application
里配置开发密钥
在application
外部声明权限声明
配置布局文件
地图初始化
新建一个类DemoApplication
继承于Application
public class DemoApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// 在SDK各功能组件使用之前都需要调用“SDKInitializer.initialize(getApplicationContext())”,因此建议在应用创建时初始化SDK引用的Context为全局变量
// 在使用SDK各组件之前初始化context信息,传入ApplicationContext
SDKInitializer.initialize(this);
// 设置坐标类型
SDKInitializer.setCoordType(CoordType.BD09LL);
}
}
并在AndroidManifest
文件中声明该Application
创建地图Activity,管理MapView声明周期
public class MainActivity extends AppCompatActivity {
private MapView mMapView = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMapView = findViewById(R.id.bmapView);
}
@Override
protected void onResume() {
super.onResume();
mMapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mMapView.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
}
}
通过添加View显示地图
百度地图支持不用通过在布局文件中添加MapView
控件,直接在Java代码中添加MapView
的方式来展示地图
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 创建MapView对象
MapView mapView = new MapView(this);
// 添加MapView对象
setContentView(mapView);
}
在Java代码中添加MapView的方式支持通过BaiduMapOption对象根据需求构造包含特定地图状态类型和控件显示状态的MapView对象
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 在Java代码中添加MapView的方式支持通过BaiduMapOption对象根据需求构造包含特定地图状态类型和控件显示状态的MapView对象
// 定义BaiduMapOptions对象
BaiduMapOptions options = new BaiduMapOptions();
// 设置需要的状态
// 设置地图为卫星模式
options.mapType(BaiduMap.MAP_TYPE_SATELLITE);
// 创建MapView对象
MapView mapView = new MapView(this, options);
// 添加MapView对象
setContentView(mapView);
}
状态 | 含义 |
---|---|
mapStatus | 地图状态 |
compassEnable | 是否开启指南针,默认开启 |
mapType | 地图模式,默认为普通地图 |
rotateGesturesEnabled | 是否允许地图旋转手势,默认允许 |
scrollGesturesEnabled | 是否允许拖拽手势,默认允许 |
overlookingGesturesEnabled | 是否允许俯视图手势,默认允许 |
zoomControlsEnabled | 是否显示缩放按钮控件,默认允许 |
zoomControlsPosition | 设置缩放控件位置 |
zoomGesturesEnabled | 是否允许缩放手势,默认允许 |
scaleControlEnabled | 是否显示比例尺控件,默认允许 |
scaleControlPosition | 设置比例尺控件位置 |
logoPosition | 设置Logo位置 |
- | - |
BaiduMap类
BaiduMap类是地图的总控制器,调用MapView的getMap()方法可得
BaiduMap mBaiduMap = mapView.getMap();
设置地图的缩放级别
MapStatus.Builder builder = new MapStatus.Builder();
builder.zoom(18.0f);
mBaiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
地图类型
类型名称 | 说明 |
---|---|
MAP_TYPE_NORMAL | 普通地图(3D地图) |
MAP_TYPE_SATELLITE | 卫星图 |
MAP_TYPE_NONE | 空白地图 |
- | - |
利用BaiduMap
的SetMapType()
方法来设置地图类型
// 普通地图
mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
实时路况图
开启交通图
mBaiduMap.setTrafficEnabled(true);
自定义路况图颜色
setCustomTrafficColor(String severeCongestion,String congestion,String slow,String smooth)
String severeCongestion —— 严重拥堵
String congestion —— 拥堵
String slow —— 缓行
String smooth —— 畅通
// 自定义路况颜色
mBaiduMap.setCustomTrafficColor("#ffba0101", "#fff33131", "#ffff9e19", "#00000000");
// 对地图状态做更新,否则可能不会触发渲染,造成样式定义无法立即生效。
MapStatusUpdate u = MapStatusUpdateFactory.zoomTo(13);
mBaiduMap.animateMapStatus(u);
百度城市热力图
注意:只有在地图层级介于11-20级时,可显示城市热力图。
//开启热力图
mBaiduMap.setBaiduHeatMapEnabled(true);
定位
Android6.0以上的系统需要动态获取权限才能定位(获取到的经纬度数据是4.9E-324的解决办法)
在Android 6.0之后,Android系统增加了动态权限授予的控制,定位权限需用户确认后,App才能拿到如基站、WIFI等信息,从而实现定位。
在Android系统升级到7.0之后,我们发现,即使用户授予了App定位权限,App依然存在无法定位成功的问题。追查原因为:授予权限与初始化位置相关类之间存在时续逻辑问题,即如果先初始化如WifiManager、TelephonyManager,再请求确认定位权限,则即使用户确认可以授予App定位权限,App后续仍然拿不到基站、WIFI等信息,从而无法定位;反之,则可以在授予权限之后正常使用定位。
针对这个情况,定位SDK自v7.2版本起,新增加了重启接口,LocationClient.reStart(),您可以在用户确认授予App定位权限之后,调用该接口,定位SDK将会进行重新初始化的操作,从而规避上述问题。您如果存在长时间后台定位的需求,推荐在应用回到前台的时候调用一次该接口,我们了解到有些手机系统会回收长时间后台获取用户位置的位置权限。
// 动态申请权限
// 将全部需要的权限放入List中,待会一次性调用ActivityCompat.requestPermissions()方法向用户申请授权
List permissionList = new ArrayList<>();
// ContextCompat.checkSelfPermission()判断用户是否已经授权
if(ContextCompat.checkSelfPermission(MainActivity2.this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// 加入List中
permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if(ContextCompat.checkSelfPermission(MainActivity2.this,
Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
// 加入List中
permissionList.add(Manifest.permission.READ_PHONE_STATE);
}
if(ContextCompat.checkSelfPermission(MainActivity2.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// 加入List中
permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
// 一次性调用ActivityCompat.requestPermissions()方法向用户申请授权
// 调用完ActivityCompat.requestPermissions()方法后,系统会弹出一个权限申请的对话框
// 之后回调onRequestPermissionsResult(),而授权的结果会封装在grantResults参数中,只需判断授权结果,若用户同意则执行业务逻辑,否则放弃操作
if (!permissionList.isEmpty()) {
String [] permissions = permissionList.toArray(new String[permissionList.size()]);
ActivityCompat.requestPermissions(MainActivity2.this, permissions, 1);
}
else {
// 业务代码
}
// 回调onRequestPermissionsResult()
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
// super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
if (grantResults.length > 0) {
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "必须同意所有权限才能使用本程序", Toast.LENGTH_LONG).show();
finish();
return;
}
}
navigate();
} else {
Toast.makeText(this,"发生未知错误", Toast.LENGTH_LONG).show();
finish();
}
break;
default:break;
}
}
配置AndroidManifest文件
在application
外部声明权限声明
在application
标签中声明定位的service组件
开启地图的定位图层
mBaiduMap.setMyLocationEnabled(true);
构造地图数据
通过继承抽象类BDAbstractListener并重写其onReceieveLocation方法来获取定位数据,并将其传给MapView。
public class MyLocationListener extends BDAbstractLocationListener {
@Override
public void onReceiveLocation(BDLocation bdLocation) {
//mapView销毁后不再处理新接收的位置
if (bdLocation == null || mapView == null) {
return;
}
// isFirstLocate变量是为了防止多次调用animateMapStatus()方法,因为将地图移动到我们当前未知只需要在程序第一次定位的时候调用即可
if (isFirstLocate) {
// 对地图状态做更新,否则可能不会触发渲染,造成样式定义无法立即生效。
//这段代码的作用:地图默认显示北京,加上下面这句让地图移动到本地
LatLng ll = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude());
MapStatus.Builder builder = new MapStatus.Builder();
builder.target(ll).zoom(18.0f);
mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
isFirstLocate = false;
}
MyLocationData locationData = new MyLocationData.Builder()
.accuracy(bdLocation.getRadius())
.direction(bdLocation.getDirection())
.latitude(bdLocation.getLatitude())
.longitude(bdLocation.getLongitude())
.build();
mBaiduMap.setMyLocationData(locationData);
}
}
通过LocationClient
发起定位,将这些业务代码封装到navigate方法里
private void navigate() {
// 如果所需权限全部授权,就执行业务逻辑
// 开启地图的定位图层
mBaiduMap.setMyLocationEnabled(true);
// 定位初始化
mLocationClient = new LocationClient(this);
// 通过LocationClientOptions设置LocationClient相关参数
option = new LocationClientOption();
option.setOpenGps(true); // 打开GPS
option.setCoorType("bd09ll"); // 设置坐标类型
option.setScanSpan(1000); // 设置发起定位请求的间隔时间
option.setIsNeedAddress(true); // 百度定位 BDLocation.getXXX() 为 null,是因为没有设置这一句
// LocationClient绑定option数据
mLocationClient.setLocOption(option);
// 注册BDAbstractLocationListener监听器
MyLocationListener myLocationListener = new MyLocationListener();
mLocationClient.registerLocationListener(myLocationListener);
// 开启地图定位图层
mLocationClient.start();
}
生命周期管理
@Override
protected void onDestroy() {
mLocationClient.stop();
mBaiduMap.setMyLocationEnabled(false);
mapView.onDestroy();
mapView = null;
super.onDestroy();
}
完整代码(使用直接用Java代码实现MapView的方式)
DemoApplication.java
在SDK各功能组件使用之前都需要调用“SDKInitializer.initialize(getApplicationContext())”,因此建议在应用创建时初始化SDK引用的Context为全局变量
package com.example.baidumaptestdemo;
import android.app.Application;
import com.baidu.mapapi.CoordType;
import com.baidu.mapapi.SDKInitializer;
public class DemoApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// 在SDK各功能组件使用之前都需要调用“SDKInitializer.initialize(getApplicationContext())”,因此建议在应用创建时初始化SDK引用的Context为全局变量
// 在使用SDK各组件之前初始化context信息,传入ApplicationContext
SDKInitializer.initialize(this);
// 设置坐标类型
SDKInitializer.setCoordType(CoordType.BD09LL);
}
}
MainActivity2.java
package com.example.baidumaptestdemo;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.BaiduMapOptions;
import com.baidu.mapapi.map.MapStatus;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.model.LatLng;
import java.util.ArrayList;
import java.util.List;
public class MainActivity2 extends AppCompatActivity {
public static final String TAG = "MyLocation--";
private MapView mapView;
private BaiduMap mBaiduMap;
private LocationClient mLocationClient;
private LocationClientOption option;
private boolean isFirstLocate = true;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 在Java代码中添加MapView的方式支持通过BaiduMapOption对象根据需求构造包含特定地图状态类型和控件显示状态的MapView对象
// 定义BaiduMapOptions对象
BaiduMapOptions options = new BaiduMapOptions();
// 设置需要的状态
// 设置地图为卫星模式
// options.mapType(BaiduMap.MAP_TYPE_SATELLITE);
// 创建MapView对象
mapView = new MapView(this, options);
// 添加MapView对象
setContentView(mapView);
// BaiduMap类是地图的总控制器,调用MapView的getMap()方法可得
mBaiduMap = mapView.getMap();
// 设置地图缩放级别
// MapStatus.Builder builder = new MapStatus.Builder();
// builder.zoom(14.0f);
// mBaiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
// 设置普通地图
// mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
// 开启交通图
// mBaiduMap.setTrafficEnabled(true);
// 自定义路况颜色
// mBaiduMap.setCustomTrafficColor("#ffba0101", "#fff33131", "#ffff9e19", "#00000000");
// 对地图状态做更新,否则可能不会触发渲染,造成样式定义无法立即生效。
// MapStatusUpdate u = MapStatusUpdateFactory.zoomTo(13);
// mBaiduMap.animateMapStatus(u);
//开启热力图
// mBaiduMap.setBaiduHeatMapEnabled(true);
// 动态申请权限
// 将全部需要的权限放入List中,待会一次性调用ActivityCompat.requestPermissions()方法向用户申请授权
List permissionList = new ArrayList<>();
// ContextCompat.checkSelfPermission()判断用户是否已经授权
if(ContextCompat.checkSelfPermission(MainActivity2.this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// 加入List中
permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if(ContextCompat.checkSelfPermission(MainActivity2.this,
Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
// 加入List中
permissionList.add(Manifest.permission.READ_PHONE_STATE);
}
if(ContextCompat.checkSelfPermission(MainActivity2.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// 加入List中
permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
// 一次性调用ActivityCompat.requestPermissions()方法向用户申请授权
// 调用完ActivityCompat.requestPermissions()方法后,系统会弹出一个权限申请的对话框
// 之后回调onRequestPermissionsResult(),而授权的结果会封装在grantResults参数中,只需判断授权结果,若用户同意则执行业务逻辑,否则放弃操作
if (!permissionList.isEmpty()) {
String [] permissions = permissionList.toArray(new String[permissionList.size()]);
ActivityCompat.requestPermissions(MainActivity2.this, permissions, 1);
}
else {
navigate();
}
}
// 定位功能封装
private void navigate() {
// 如果所需权限全部授权,就执行业务逻辑
// 开启地图的定位图层
mBaiduMap.setMyLocationEnabled(true);
// 定位初始化
mLocationClient = new LocationClient(this);
// 通过LocationClientOptions设置LocationClient相关参数
option = new LocationClientOption();
option.setOpenGps(true); // 打开GPS
option.setCoorType("bd09ll"); // 设置坐标类型
option.setScanSpan(1000); // 设置发起定位请求的间隔时间
option.setIsNeedAddress(true); // 百度定位 BDLocation.getXXX() 为 null,是因为没有设置这一句
// LocationClient绑定option数据
mLocationClient.setLocOption(option);
// 注册BDAbstractLocationListener监听器
MyLocationListener myLocationListener = new MyLocationListener();
mLocationClient.registerLocationListener(myLocationListener);
// 开启地图定位图层
mLocationClient.start();
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
// super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
if (grantResults.length > 0) {
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "必须同意所有权限才能使用本程序", Toast.LENGTH_LONG).show();
finish();
return;
}
}
navigate();
} else {
Toast.makeText(this,"发生未知错误", Toast.LENGTH_LONG).show();
finish();
}
break;
default:break;
}
}
// 通过继承抽象类BDAbstractListener并重写其onReceieveLocation方法来获取定位数据,并将其传给MapView。
public class MyLocationListener extends BDAbstractLocationListener {
@Override
public void onReceiveLocation(BDLocation bdLocation) {
//mapView销毁后不再处理新接收的位置
if (bdLocation == null || mapView == null) {
return;
}
if (isFirstLocate) {
Log.d(TAG, "hello");
String addstr = bdLocation.getAddrStr();
double lati = bdLocation.getLatitude();
double longi = bdLocation.getLongitude();
Log.d(TAG, addstr);
boolean isNull = bdLocation == null;
Log.d(TAG, String.valueOf(isNull));
// 对地图状态做更新,否则可能不会触发渲染,造成样式定义无法立即生效。
//这段代码的作用:地图默认显示北京,加上下面这句让地图移动到本地
LatLng ll = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude());
MapStatus.Builder builder = new MapStatus.Builder();
builder.target(ll).zoom(18.0f);
mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
isFirstLocate = false;
}
MyLocationData locationData = new MyLocationData.Builder()
.accuracy(bdLocation.getRadius())
.direction(bdLocation.getDirection())
.latitude(bdLocation.getLatitude())
.longitude(bdLocation.getLongitude())
.build();
mBaiduMap.setMyLocationData(locationData);
}
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onDestroy() {
mLocationClient.stop();
mBaiduMap.setMyLocationEnabled(false);
mapView.onDestroy();
mapView = null;
super.onDestroy();
}
}
AndroidManifest.xml