上一节咱们介绍了百度定位sdk,这一节咱们在定位的基础上介绍百度地图sdk。html
首先把上一节布局文件中添加的textview删掉,而后加入MapView这个控件:java
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.lbstest.MainActivity">
<com.baidu.mapapi.map.MapView android:id="@+id/mapView" android:layout_width="match_parent" android:layout_height="match_parent" android:clickable="true"/>
</android.support.constraint.ConstraintLayout>
毫无疑问这个控件就是显示地图的。
接着咱们对Activity作如下修改:android
private MapView mMapView;
private BaiduMap mBaiduMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mlocation = new LocationClient(getApplicationContext());
mlocation.registerLocationListener(new MyLocationListener());
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_main);
//初始化方向传感器
myOrientationListener = new MyOrientationListener(this);
//获取地图控件引用
mMapView = (MapView) findViewById(R.id.mapView);
mBaiduMap = mMapView.getMap();
//申请权限
initPermission();
}
@Override
protected void onResume() {
super.onResume();
//在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理
mMapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
//在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理
mMapView.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
mlocation.stop();
//在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
mMapView.onDestroy();
}
和上一节相比多了SDKInitializer初始化、获取MapView实例和获取BaiduMap的实例(BaiduMap是地图的总控制器,它能够对地图进行各类各样的操做),另外还须要重写onDestroy() 、onPause()、 onResume() 这3个方法对MapView进行管理,以保证资源可以及时释放。到这里地图已经可以显示出来了。git
聪明的你必定发现咱们并无设置坐标,这样是不能显示到咱们的位置的, 下面咱们让地图显示到咱们的位置。
这就须要咱们上一节中定位sdk的知识了,首先咱们把BDLocationListener作一下修改:web
public class MyLocationListener implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation bdLocation) {
mCurrentAccracy=bdLocation.getRadius();
mCurrentLantitude=bdLocation.getLatitude();
mCurrentLongitude=bdLocation.getLongitude();
if (bdLocation.getLocType() == BDLocation.TypeGpsLocation || bdLocation.getLocType() == BDLocation.TypeNetWorkLocation) {
//设置地图显示
navigateTo(bdLocation);
}
}
@Override
public void onConnectHotSpotMessage(String s, int i) {
}
}
private void navigateTo(BDLocation location) {
if (isFirstLocate) {
//定位坐标
LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
mBaiduMap.animateMapStatus(update);
//设置缩放级别
update = MapStatusUpdateFactory.zoomTo(21f);
mBaiduMap.animateMapStatus(update);
isFirstLocate = false;
}
}
上面的代码首先在定位回调的函数中将经纬度信息赋值给全局变量,这是在后面使用的咱们暂时不看,而后判断是否认位成功,成功后调用navigateTo()方法,在navigateTo()方法中经过一个boolean全局变量判断是不是第一次定位,然户设置定位坐标,缩放级别(其余的设置属性参照官方文档,这里就很少介绍了),如今地图就已经显示在咱们的位置了。api
运行效果:
app
咱们用的地图都会有一个图标显示在咱们的位置,下面咱们来添加这个图标。
首先要在onCreate()方法中调用BaiduMap的setMyLocationEnabled方法开启此功能:ide
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mlocation = new LocationClient(getApplicationContext());
mlocation.registerLocationListener(new MyLocationListener());
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_main);
//初始化方向传感器
myOrientationListener = new MyOrientationListener(this);
//获取地图控件引用
mMapView = (MapView) findViewById(R.id.mapView);
mBaiduMap = mMapView.getMap();
mBaiduMap.setMyLocationEnabled(true);
//申请权限
initPermission();
}
接着在navigateTo方法中添加MyLocationData的构建逻辑:svg
private void navigateTo(BDLocation location) {
if (isFirstLocate) {
//定位坐标
LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
mBaiduMap.animateMapStatus(update);
//设置缩放级别
update = MapStatusUpdateFactory.zoomTo(21f);
mBaiduMap.animateMapStatus(update);
isFirstLocate = false;
}
MyLocationData.Builder builder = new MyLocationData.Builder();
builder.accuracy(mCurrentAccracy);
builder.latitude(mCurrentLantitude);
builder.longitude(mCurrentLongitude);
MyLocationData locationData = builder.build();
mBaiduMap.setMyLocationData(locationData);
}
这里用到了mCurrentAccracy、mCurrentLantitude、mCurrentLongitude这三个保存了经纬度信息的全局变量,MyLocationConfiguration 的最后一个参数设置图标的样式,传入空为默认图标,固然也能够传入一个BitmapDescriptor设置自定义图标。
最后在onDestroy()方法中关闭此功能:函数
@Override
protected void onDestroy() {
super.onDestroy();
mlocation.stop();
//在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
mMapView.onDestroy();
mBaiduMap.setMyLocationEnabled(false);
}
到这里显示定位图标就完成了。
运行效果:
虽然当前位置的图标显示出来了,可是对于一些路痴来讲(好比我)仍然找不到方向,这就须要显示方向了,显示方向的功能实现须要手机的加速度和地磁场传感器,根据这两个传感器计算出手机的角度,而后将这个角度传给MyLocationData.Builder的builder.direction()方法用于设置方向。下面咱们开始实现这一功能。
在往下看以前建议先看一下一篇关于传感器的文章:http://www.2cto.com/kf/201412/359292.html
首先建立一个类MyOrientationListener,全部传感器的操做都封装在这个类中:
public class MyOrientationListener implements SensorEventListener {
private Context context;
private SensorManager sensorManager;
private Sensor accelerometer; // 加速度传感器
private Sensor magnetic; // 地磁场传感器
private float[] accelerometerValues = new float[3];
private float[] magneticFieldValues = new float[3];
private float lastX;
private OnOrientationListener onOrientationListener ;
public MyOrientationListener(Context context)
{
this.context = context;
}
@Override
public void onSensorChanged(SensorEvent event) {
// 接受方向感应器的类型
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
accelerometerValues = event.values;
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
magneticFieldValues = event.values;
}
getOrientation();
}
public void getOrientation() {
float[] values = new float[3];
float[] R = new float[9];
SensorManager.getRotationMatrix(R, null, accelerometerValues, magneticFieldValues);
//将角度信息计算后返回到values中
SensorManager.getOrientation(R, values);
values[0] = (float) Math.toDegrees(values[0]);
//当方向的改变大于一度时回调监听
if( Math.abs(values[0]- lastX) > 1.0 )
{
onOrientationListener.onOrientationChanged(values[0]);
}
lastX = values[0] ;
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
public void start(){
// 得到传感器管理器
sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
if (sensorManager != null)
{
// 初始化加速度传感器
accelerometer = sensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
// 初始化地磁场传感器
magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
}
// 注册
if (accelerometer != null || magnetic!=null)
{
sensorManager.registerListener(this,
accelerometer, Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(this, magnetic,
Sensor.TYPE_MAGNETIC_FIELD);
}
}
public void stop() {
sensorManager.unregisterListener(this);
}
public void setOnOrientationListener(OnOrientationListener onOrientationListener) {
this.onOrientationListener = onOrientationListener;
}
public interface OnOrientationListener{
void onOrientationChanged(float x);
}
}
若是你看了我推荐的那篇文章上面的代码对你来讲就是小菜一碟,注释也写得清楚我就不详细介绍了,使用时只需建立一个实例,而后调用start()方法,在设置监听就能够了,最后别忘了stop()。
咱们在咱们Activity实现这个类:
首先在oncreat()方法中实例化这个类,并设置监听,把接收的参数赋值给一个全局变量:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mlocation = new LocationClient(getApplicationContext());
mlocation.registerLocationListener(new MyLocationListener());
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_main);
//初始化方向传感器
myOrientationListener = new MyOrientationListener(this);
myOrientationListener.setOnOrientationListener(this);
//获取地图控件引用
mMapView = (MapView) findViewById(R.id.mapView);
mBaiduMap = mMapView.getMap();
mBaiduMap.setMyLocationEnabled(true);
//申请权限
initPermission();
}
接着在onResume()方法中调用MyOrientationListener的start()方法:
@Override
protected void onResume() {
super.onResume();
//在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理
mMapView.onResume();
myOrientationListener.start();
}
而后把navigateTo()方法中对MyLocationData.Builder的配置删掉:
private void navigateTo(BDLocation location) {
if (isFirstLocate) {
//定位坐标
LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
mBaiduMap.animateMapStatus(update);
//设置缩放级别
update = MapStatusUpdateFactory.zoomTo(21f);
mBaiduMap.animateMapStatus(update);
isFirstLocate = false;
}
}
最后在MyOrientationListener的监听方法中添加如下代码:
@Override
public void onOrientationChanged(float x) {
mXDirection = (int) x;
builder = new MyLocationData.Builder();
builder.accuracy(mCurrentAccracy);
builder.direction(mXDirection);
builder.latitude(mCurrentLantitude);
builder.longitude(mCurrentLongitude);
MyLocationData locationData = builder.build();
mBaiduMap.setMyLocationData(locationData);
// 设置自定义图标
//BitmapDescriptor mCurrentMarker = BitmapDescriptorFactory.fromResource(R.drawable.arrow);
MyLocationConfiguration configuration = new MyLocationConfiguration(MyLocationConfiguration.LocationMode.NORMAL, true, null);
mBaiduMap.setMyLocationConfiguration(configuration);
}
咱们对MyLocationData增长了一个设置builder.direction(mXDirection)。最后还要用MyLocationConfiguration对BaiduMap进行配置,MyLocationConfiguration的第一个参数为图标显示模式,有三种模式我就不一一介绍了,有兴趣的同窗能够本身试试,或者参考官方文档,第二个参数表示是否显示方向,第三个参数为自定义图标,若是使用默认图标传入空就好了。
最后别忘了在onDestroy()方法中stop方向传感器:
@Override
protected void onDestroy() {
super.onDestroy();
mlocation.stop();
//在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
mMapView.onDestroy();
mBaiduMap.setMyLocationEnabled(false);
}
运行效果:
到这里百度地图sdk的初使用也完成了,下面是完整的代码:
public class MainActivity extends AppCompatActivity implements MyOrientationListener.OnOrientationListener{
private MapView mMapView;
private BaiduMap mBaiduMap;
private List<String> permissionList;
private Boolean isFirstLocate=true;
private float mCurrentAccracy;
private double mCurrentLantitude;
private double mCurrentLongitude;
private int mXDirection;
public LocationClient mlocation;
private MyLocationData.Builder builder;
private MyOrientationListener myOrientationListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mlocation = new LocationClient(getApplicationContext());
mlocation.registerLocationListener(new MyLocationListener());
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_main);
//初始化方向传感器
myOrientationListener = new MyOrientationListener(this);
myOrientationListener.setOnOrientationListener(this);
//获取地图控件引用
mMapView = (MapView) findViewById(R.id.mapView);
mBaiduMap = mMapView.getMap();
mBaiduMap.setMyLocationEnabled(true);
//申请权限
initPermission();
}
private void initPermission() {
permissionList = new ArrayList<>();
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.READ_PHONE_STATE);
}
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (!permissionList.isEmpty()) {
String[] permissions = permissionList.toArray(new String[permissionList.size()]);
ActivityCompat.requestPermissions(MainActivity.this, permissions, 1);
} else {
//请求定位
requestLocation();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0) {
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(MainActivity.this, "必须赞成全部权限", Toast.LENGTH_LONG).show();
finish();
return;
}
}
//请求定位
requestLocation();
} else {
finish();
}
break;
}
}
private void requestLocation() {
//设置定位属性
initLocation();
//开始定位
mlocation.start();
}
private void initLocation() {
LocationClientOption option = new LocationClientOption();
option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
//设置百度坐标
option.setCoorType("bd09ll");
option.setOpenGps(true); // 打开gps
//设置定位延迟
option.setScanSpan(3000);
mlocation.setLocOption(option);
}
@Override
public void onOrientationChanged(float x) {
mXDirection = (int) x;
builder = new MyLocationData.Builder();
builder.accuracy(mCurrentAccracy);
builder.direction(mXDirection);
builder.latitude(mCurrentLantitude);
builder.longitude(mCurrentLongitude);
MyLocationData locationData = builder.build();
mBaiduMap.setMyLocationData(locationData);
// 设置自定义图标
//BitmapDescriptor mCurrentMarker = BitmapDescriptorFactory.fromResource(R.drawable.arrow);
MyLocationConfiguration configuration = new MyLocationConfiguration(MyLocationConfiguration.LocationMode.NORMAL, true, null);
mBaiduMap.setMyLocationConfiguration(configuration);
}
public class MyLocationListener implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation bdLocation) {
mCurrentAccracy=bdLocation.getRadius();
mCurrentLantitude=bdLocation.getLatitude();
mCurrentLongitude=bdLocation.getLongitude();
if (bdLocation.getLocType() == BDLocation.TypeGpsLocation || bdLocation.getLocType() == BDLocation.TypeNetWorkLocation) {
//设置地图显示
navigateTo(bdLocation);
}
}
@Override
public void onConnectHotSpotMessage(String s, int i) {
}
}
private void navigateTo(BDLocation location) {
if (isFirstLocate) {
//定位坐标
LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
mBaiduMap.animateMapStatus(update);
//设置缩放级别
update = MapStatusUpdateFactory.zoomTo(21f);
mBaiduMap.animateMapStatus(update);
isFirstLocate = false;
}
}
@Override
protected void onResume() {
super.onResume();
//在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理
mMapView.onResume();
myOrientationListener.start();
}
@Override
protected void onPause() {
super.onPause();
//在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理
mMapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
myOrientationListener.stop();
}
@Override
protected void onDestroy() {
super.onDestroy();
mlocation.stop();
//在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
mMapView.onDestroy();
mBaiduMap.setMyLocationEnabled(false);
}
}
public class MyOrientationListener implements SensorEventListener {
private Context context;
private SensorManager sensorManager;
private Sensor accelerometer; // 加速度传感器
private Sensor magnetic; // 地磁场传感器
private float[] accelerometerValues = new float[3];
private float[] magneticFieldValues = new float[3];
private float lastX;
private OnOrientationListener onOrientationListener ;
public MyOrientationListener(Context context)
{
this.context = context;
}
@Override
public void onSensorChanged(SensorEvent event) {
// 接受方向感应器的类型
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
accelerometerValues = event.values;
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
magneticFieldValues = event.values;
}
getOrientation();
}
public void getOrientation() {
float[] values = new float[3];
float[] R = new float[9];
SensorManager.getRotationMatrix(R, null, accelerometerValues, magneticFieldValues);
//将角度信息计算后返回到values中
SensorManager.getOrientation(R, values);
values[0] = (float) Math.toDegrees(values[0]);
//当方向的改变大于一度时回调监听
if( Math.abs(values[0]- lastX) > 1.0 )
{
onOrientationListener.onOrientationChanged(values[0]);
}
lastX = values[0] ;
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
public void start(){
// 得到传感器管理器
sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
if (sensorManager != null)
{
// 初始化加速度传感器
accelerometer = sensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
// 初始化地磁场传感器
magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
}
// 注册
if (accelerometer != null || magnetic!=null)
{
sensorManager.registerListener(this,
accelerometer, Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(this, magnetic,
Sensor.TYPE_MAGNETIC_FIELD);
}
}
public void stop() {
sensorManager.unregisterListener(this);
}
public void setOnOrientationListener(OnOrientationListener onOrientationListener) {
this.onOrientationListener = onOrientationListener;
}
public interface OnOrientationListener{
void onOrientationChanged(float x);
}
}