android百度地图开发——地图sdk之基础地图

上一节咱们介绍了百度定位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);
    }
}