Android 百度定位SDK(v6.1.3)结合方向传感器

Posted 一口仨馍

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 百度定位SDK(v6.1.3)结合方向传感器相关的知识,希望对你有一定的参考价值。

概述

这是第二篇关于百度地图SDK的博客。

推荐阅读:
Android 百度地图周边雷达(v6.1.3)

Android 百度鹰眼轨迹SDK(v2.1.6)

今天主要写百度地图定位和方向传感器结合这么一个中间块案例。

流程

  1. 申请密钥及相关配置请看:http://lbsyun.baidu.com/index.php?title=android-locsdk/guide/buildprojec
  2. 初始化百度地图SDK
  3. 定位到当前位置
  4. 获取方向传感器方向
  5. 设定到百度地图SDK

    努力总会有收获,go!

    为了节省篇幅以及不必要的解释,假设你已经配置好了百度定位SDK。如果没有,请见:http://lbsyun.baidu.com/index.php?title=android-locsdk/guide/buildprojec

按照百度地图SDK,初始化相关组件。

        //在使用SDK各组件之前初始化context信息,传入ApplicationContext
        //注意该方法要再setContentView方法之前实现
        SDKInitializer.initialize(getApplicationContext());
        setContentView(R.layout.activity_main);
        testLocation();

在testLocation()里我们注册了mLocationClient的LocationListener以及初始化LocationClientOption。相关代码及详细注释如下

    public LocationClient mLocationClient = null;
    public BDLocationListener myListener = new MyLocationListener();

    private void testLocation() 
        mLocationClient = new LocationClient(getApplicationContext());     //声明LocationClient类
        mLocationClient.registerLocationListener(myListener);    //注册监听函数

        /**
         * 高精度定位模式:这种定位模式下,会同时使用网络定位和GPS定位,优先返回最高精度的定位结果;
         * 低功耗定位模式:这种定位模式下,不会使用GPS,只会使用网络定位(Wi-Fi和基站定位);
         * 仅用设备定位模式:这种定位模式下,不需要连接网络,只使用GPS进行定位,这种模式下不支持室内环境的定位。
         */
        LocationClientOption option = new LocationClientOption();
        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy
        );//可选,默认高精度,设置定位模式,高精度,低功耗,仅设备
        option.setCoorType("bd09ll");//可选,默认gcj02,设置返回的定位结果坐标系
        int span = 1000;
        option.setScanSpan(span);//可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的
        option.setIsNeedAddress(true);//可选,设置是否需要地址信息,默认不需要
        option.setOpenGps(true);//可选,默认false,设置是否使用gps
        option.setLocationNotify(true);//可选,默认false,设置是否当gps有效时按照1S1次频率输出GPS结果
        option.setIsNeedLocationDescribe(true);//可选,默认false,设置是否需要位置语义化结果,可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近”
        option.setIsNeedLocationPoiList(true);//可选,默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到
        option.setIgnoreKillProcess(false);//可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死
        option.SetIgnoreCacheException(true);//可选,默认false,设置是否收集CRASH信息,默认收集
        option.setEnableSimulateGps(false);//可选,默认false,设置是否需要过滤gps仿真结果,默认需要
        mLocationClient.setLocOption(option);
    

细心的同学会看到,这里我们实现了一个自己的Listener。

    private class MyLocationListener implements BDLocationListener 

        @Override
        public void onReceiveLocation(BDLocation location) 
            //mapview 销毁后不在处理新接收的位置
            if (location == null || mBaiduMap == null) 
                return;
            

            getLocationInfo(location);
            // 开启定位图层
            mBaiduMap.setMyLocationEnabled(true);
            // 构造定位数据
            final MyLocationData locData = new MyLocationData.Builder()
                    .accuracy(location.getRadius())
                    // 此处设置开发者获取到的方向信息,顺时针0-360
                    .direction(100)
                    .latitude(location.getLatitude())
                    .longitude(location.getLongitude())
                    .build();
            // 设置定位数据
            mBaiduMap.setMyLocationData(locData);
            if (isFirstGetLocation) 
                isFirstGetLocation = false;
                // 获取经纬度
                LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
                // 设置地图中心点以及缩放级别
                MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLngZoom(latLng, 15);
                mBaiduMap.animateMapStatus(mapStatusUpdate);
            
//            Log.i(TAG, "latitude:"+mBaiduMap.getLocationData().latitude +
//                        "\\nlongitude:"+mBaiduMap.getLocationData().longitude +
//                        "\\ndirection:"+mBaiduMap.getLocationData().direction);
            // 设置定位图层的配置(定位模式,是否允许方向信息,用户自定义定位图标)
            mCurrentMarker = BitmapDescriptorFactory.fromResource(R.mipmap.location_pic);
            MyLocationConfiguration config = new MyLocationConfiguration(MyLocationConfiguration.LocationMode.NORMAL,
                    true, mCurrentMarker);
            mBaiduMap.setMyLocationConfigeration(config);


        
     

我们的listener实现了BDLocationListener接口。复写了onReceiveLocation()方法。就像方法的名字,收到定位信息后会调用此方法。因此,在此方法里我们可以实现收到定位信息后自己的逻辑。这样我们就有了一个最初始的百度地图。位置更详细的信息在getLocationInfo()方法里。一般需要的信息都可以在此找到。

        private void getLocationInfo(BDLocation location) 
            //Receive Location
            StringBuffer sb = new StringBuffer(256);
            sb.append("time : ");
            sb.append(location.getTime());
            sb.append("\\nerror code : ");
            sb.append(location.getLocType());
            sb.append("\\nlatitude : ");
            sb.append(location.getLatitude());
            sb.append("\\nlontitude : ");
            sb.append(location.getLongitude());
            sb.append("\\nradius : ");
            sb.append(location.getRadius());
            if (location.getLocType() == BDLocation.TypeGpsLocation) // GPS定位结果
                sb.append("\\nspeed : ");
                sb.append(location.getSpeed());// 单位:公里每小时
                sb.append("\\nsatellite : ");
                sb.append(location.getSatelliteNumber());
                sb.append("\\nheight : ");
                sb.append(location.getAltitude());// 单位:米
                sb.append("\\ndirection : ");
                sb.append(location.getDirection());// 单位度
                sb.append("\\naddr : ");
                sb.append(location.getAddrStr());
                sb.append("\\ndescribe : ");
                sb.append("gps定位成功");

             else if (location.getLocType() == BDLocation.TypeNetWorkLocation) // 网络定位结果
                sb.append("\\naddr : ");
                sb.append(location.getAddrStr());
                //运营商信息
                sb.append("\\noperationers : ");
                sb.append(location.getOperators());
                sb.append("\\ndescribe : ");
                sb.append("网络定位成功");
             else if (location.getLocType() == BDLocation.TypeOffLineLocation) // 离线定位结果
                sb.append("\\ndescribe : ");
                sb.append("离线定位成功,离线定位结果也是有效的");
             else if (location.getLocType() == BDLocation.TypeServerError) 
                sb.append("\\ndescribe : ");
                sb.append("服务端网络定位失败,可以反馈IMEI号和大体定位时间到loc-bugs@baidu.com,会有人追查原因");
             else if (location.getLocType() == BDLocation.TypeNetWorkException) 
                sb.append("\\ndescribe : ");
                sb.append("网络不同导致定位失败,请检查网络是否通畅");
             else if (location.getLocType() == BDLocation.TypeCriteriaException) 
                sb.append("\\ndescribe : ");
                sb.append("无法获取有效定位依据导致定位失败,一般是由于手机的原因,处于飞行模式下一般会造成这种结果,可以试着重启手机");
            
            sb.append("\\nlocationdescribe : ");
            sb.append(location.getLocationDescribe());// 位置语义化信息,结果类似于“在北京天安门附近”
            List<Poi> list = location.getPoiList();// POI数据
            if (list != null) 
                sb.append("\\npoilist size = : ");
                sb.append(list.size());
                for (Poi p : list) 
                    sb.append("\\npoi= : ");
                    sb.append(p.getId() + " " + p.getName() + " " + p.getRank());
                
            
            Log.i(TAG, sb.toString());
        

至此,我们百度定位SDK的就完事了。假设我们想做到旋转手机的时候旋转location_pic对应的方向怎么办呢?答案就是结合方向传感器啦!中间体,这也是本篇博客的主要所在。

方向传感器简介

  1. 手机的自然坐标系
    当一个设备被放在其默认的方向上时,X轴是水平指向右的,Y轴是垂直向上的,Z轴是指向屏幕正面之外的,即屏幕背面是Z的负值
  2. 方向传感器是利用加速度计和地磁场传感器得到自己的数据。方向传感器比较特殊,因为它的数值是相对于绝对方向的。它得到的是手机设备的绝对姿态值。
    方向传感器返回的都是角度值,以度数为单位。

我们只用到X轴坐标:表示手机自身的y轴与地磁场北极方向的角度,即手机顶部朝向与正北方向的角度。(This is the angle between magnetic north and the device’s y axis. )当手机绕着自身的z轴旋转时,该角度值将发生改变。例如该角度值为0时,表示手机顶部指向正北;该角度为90度时,代表手机顶部指向正东;该角度为180度时,代表手机顶部指向正南;该角度为270度时,代表手机顶部指向正西。

写一个自己的方向传感器

package com.dyk.baidumapwork;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;

/**
 * Created by dyk on 2016/3/22.
 */
public class OrientationSensor implements SensorEventListener 

    private static final String TAG = "BaiduMap";
    private Context mContext;
    private SensorManager mSensorManager;
    private Sensor defaultSensor;
    private float lastX;
    private OrientationSensorListener mOrientationSensorListener;

    public OrientationSensor(Context context) 
        this.mContext = context;
    

    public void start() 
        mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
        defaultSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
        mSensorManager.registerListener(this, defaultSensor, SensorManager.SENSOR_DELAY_NORMAL);
    

    public void stop() 
        mSensorManager.unregisterListener(this, defaultSensor);
    

    @Override
    public void onSensorChanged(SensorEvent event) 
        Log.i(TAG,event.values[0]+"  "+event.values[1]+"  "+event.values[2]);
        if (mOrientationSensorListener != null && (Math.abs(event.values[0] - lastX)) > 1)
            mOrientationSensorListener.getOrientation(event.values[0]);
            lastX = event.values[0];
        

    

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) 

    

    public interface OrientationSensorListener
        void getOrientation(float x);
    

    public void setOrientationListener(OrientationSensorListener orientationSensorListener)
        this.mOrientationSensorListener = orientationSensorListener;
    

可以看到,在此我们实现了SensorEventListener接口,并复写了onSensorChanged()和onAccuracyChanged()方法。这里我们用到onSensorChanged的参数event.values[0]获取X轴坐标。这里尴尬的事情来了,这里不断的变化,怎么传递给activity?接口!
这里我们定义了一个OrientationSensorListener接口,只有一个方法。getOrientation(float x)

    private OrientationSensorListener mOrientationSensorListener;

    public interface OrientationSensorListener
        void getOrientation(float x);
    

    public void setOrientationListener(OrientationSensorListener orientationSensorListener)
        this.mOrientationSensorListener = orientationSensorListener;
    

在onSensorChanged()方法中我们可以调用OrientationSensorListener#getOrientation(float x),并且把X轴坐标event.values[0]当做参数传递进去,接着在activity里实现接口,获取数据,设定方向。代码如下

    private OrientationSensor mOrientationSensor;
    /**
     * 传感器方向
     */
    private float driection = 0;

    mOrientationSensor = new OrientationSensor(this);
    mOrientationSensor.start();

    private class MyLocationListener implements BDLocationListener 

        @Override
        public void onReceiveLocation(BDLocation location) 

            mOrientationSensor.setOrientationListener(new OrientationSensor.OrientationSensorListener() 
                @Override
                public void getOrientation(float x) 
                    driection = x;
                
            );

       final MyLocationData locData = new MyLocationData.Builder()
                    .accuracy(location.getRadius())
                    // 此处设置开发者获取到的方向信息,顺时针0-360
                    .direction(driection)
                    .latitude(location.getLatitude())
                    .longitude(location.getLongitude())
                    .build();
       Log.i(TAG, "driection=" + driection);
       // 设置定位数据
       mBaiduMap.setMyLocationData(locData);

        
    

至此就成功的将方向传感器的数据传递到了百度地图中。最后不要忘了释放资源。

    @Override
    protected void onDestroy() 
        super.onDestroy();
        //在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
        mMapView.onDestroy();

        if (mLocationClient.isStarted()) 
            mLocationClient.stop();
        

        if (mBaiduMap.isMyLocationEnabled()) 
            // 当不需要定位图层时关闭定位图层
            mBaiduMap.setMyLocationEnabled(false);
        

        //反注册OrientationSensor
        if (mOrientationSensor != null) 
            mOrientationSensor.stop();
        
    

欢迎访问我的博客及另外两篇关于百度地图SDK的博文,综合使用可以实现更多效果:

  1. 我的博客

  2. Android 百度地图周边雷达(v6.1.3)及覆盖物

  3. Android 百度鹰眼轨迹SDK(v2.1.6)

Demo全部代码及资源下载:http://download.csdn.net/detail/qq_17250009/9469613

以上是关于Android 百度定位SDK(v6.1.3)结合方向传感器的主要内容,如果未能解决你的问题,请参考以下文章

Android 百度鹰眼轨迹SDK(v2.1.6)

Android 百度地图周边雷达(v6.1.3)及覆盖物

Android 百度地图 SDK v3.0.0 定位与结合方向传感器

Android开发 百度地图开发(定位传感器应用)

android使用百度地图SDK获取定位信息

Android利用百度地图SDK定位问题,如何更加精准