文章目录
前言添加传感器类修改MainActivity.java测试优化平滑方向变化新增对象获取上一次定位数据修改initOrientation再次定位,画面中心点不再回到定位点迅速返回定位点添加按钮实现按钮定位点模式切换添加单选框实现功能源码前言
上午刚说不知道怎么绑定方向传感器,下午就找到教程了……
主要参考了花海ipa大大的这篇文章
-详细Android Studio开发百度地图(3)—百度地图_配合方向感应器的定位功能的实现
之前对于定位的方向,是通过getDirection()来实现的,说是获取手机朝向,但是你不到处走动,图标的朝向一直不变,也不知道是它是怎么运行的。既然自带的方法不行,那就自己通过方向传感器获取一个方向。
添加传感器类
右键存放MainActivity.java文件的那个文件夹,New中选择Java Class,命名为MyOrientationListener
以下为代码,复制粘贴即可(注意文件最顶端有一个package,不要覆盖了)
import android.content.Context;import android.hardware.Sensor;import android.hardware.SensorEvent;import android.hardware.SensorEventListener;import android.hardware.SensorManager;public class MyOrientationListener implements SensorEventListener{private SensorManager mSensorManager;private Context mContext;private Sensor mSensor;private float lastX;public MyOrientationListener(Context context){this.mContext = context;}@SuppressWarnings("deprecation")public void start(){mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);if (mSensorManager != null){// 获得方向传感器mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);}if (mSensor != null){mSensorManager.registerListener(this, mSensor,SensorManager.SENSOR_DELAY_UI);}}public void stop(){mSensorManager.unregisterListener(this);}@Overridepublic void onAccuracyChanged(Sensor arg0, int arg1){// TODO Auto-generated method stub}@SuppressWarnings({"deprecation" })@Overridepublic void onSensorChanged(SensorEvent event){if (event.sensor.getType() == Sensor.TYPE_ORIENTATION){float x = event.values[SensorManager.DATA_X];if (Math.abs(x - lastX) > 1.0){if (mOnOrientationListener != null){mOnOrientationListener.onOrientationChanged(x);}}lastX = x;}}private OnOrientationListener mOnOrientationListener;public void setOnOrientationListener(OnOrientationListener mOnOrientationListener){this.mOnOrientationListener = mOnOrientationListener;}public interface OnOrientationListener{void onOrientationChanged(float x);}}
修改MainActivity.java
添加新对象
//方向传感器private MyOrientationListener mMyOrientationListener;private float mCurrentX;
初始化传感器
//传感器private void initOrientation() {//传感器mMyOrientationListener = new MyOrientationListener(getApplicationContext());mMyOrientationListener.setOnOrientationListener(new MyOrientationListener.OnOrientationListener() {@Overridepublic void onOrientationChanged(float x) {mCurrentX = x;}});}
在修改初始化地图函数
private void initmap() throws Exception {//定位初始化mLocationClient = new LocationClient(getApplicationContext());mLocationClient.registerLocationListener(new MyLocationListener());//获取地图控件引用mMapView = (MapView) findViewById(R.id.bmapView);mBaiduMap = mMapView.getMap();mBaiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(new MapStatus.Builder().zoom(20).build()));//开启地图的定位图层mBaiduMap.setMyLocationEnabled(true);//通过LocationClientOption设置LocationClient相关参数LocationClientOption option = new LocationClientOption();option.setOpenGps(true); // 打开gpsoption.setCoorType("bd09ll"); // 设置坐标类型option.setIsNeedAddress(true);//设置是否需要地址信息option.setScanSpan(1000);//设置locationClientOptionmLocationClient.setLocOption(option);//注册LocationListener监听器MyLocationListener myLocationListener = new MyLocationListener();mLocationClient.registerLocationListener(myLocationListener);//新增注册监听函数initOrientation();//开启地图定位图层mLocationClient.start();}
修改onReceiveLocation函数,将direction中的参数换成方向传感器获取到的方向。
MyLocationData locData = new MyLocationData.Builder().accuracy(location.getRadius())// 此处设置开发者获取到的方向信息,顺时针0-360.direction(mCurrentX).latitude(location.getLatitude()).longitude(location.getLongitude()).build();
管理生命周期
protected void onStart() {super.onStart();//开启定位mBaiduMap.setMyLocationEnabled(true);if (!mLocationClient.isStarted())mLocationClient.start();//开启方向传感器mMyOrientationListener.start();}@Overrideprotected void onStop() {super.onStop();//停止定位mBaiduMap.setMyLocationEnabled(false);mLocationClient.stop();//停止方向传感器mMyOrientationListener.stop();}
测试
由于SDK支持的最短刷新间隔就是1000ms(一秒),所以看起来会一卡一卡的,而且由于每次定位顺带把界面中心也移动到了定位点,导致想看看周围却发现不管怎么拖动地图,一会地图又回来了。
优化
平滑方向变化
虽然百度地图SDK的定位是一秒一次的,但是我们的运动传感器不是一秒一次获取方向的。根据代码我们可以看到,只要方向变化超过1°,就会传一次方向数据。
public void onSensorChanged(SensorEvent event){if (event.sensor.getType() == Sensor.TYPE_ORIENTATION){float x = event.values[SensorManager.DATA_X];if (Math.abs(x - lastX) > 1.0){if (mOnOrientationListener != null){mOnOrientationListener.onOrientationChanged(x);}}lastX = x;}}
那么,我们就在传回方向的时候重新修改定位点数据。
新增对象
//记录当前经纬度以及定位精度private double Latitude;private double Longitude;private float Radius;
获取上一次定位数据
在onReceiveLocation中添加以下代码
Latitude=location.getLatitude();Longitude=location.getLongitude();Radius=location.getRadius();
修改initOrientation
//传感器private void initOrientation() {//传感器mMyOrientationListener = new MyOrientationListener(getApplicationContext());mMyOrientationListener.setOnOrientationListener(new MyOrientationListener.OnOrientationListener() {@Overridepublic void onOrientationChanged(float x) {mCurrentX = x;MyLocationData locData = new MyLocationData.Builder().accuracy(Radius).direction(mCurrentX).latitude(Latitude).longitude(Longitude).build();mBaiduMap.setMyLocationData(locData);}});}
这样就能在方向变化时立即反应到地图上。
再次定位,画面中心点不再回到定位点
新增对象
//是否为初次定位private boolean isFirst = true;
在onReceiveLocation中加入判断条件
if(isFirst){mBaiduMap.animateMapStatus(update);MyLocationConfiguration configuration = new MyLocationConfiguration(MyLocationConfiguration.LocationMode.NORMAL,true, null );mBaiduMap.setMyLocationConfiguration(configuration);isFirst=false;}
这样,只有第一次定位重置地图位置。
迅速返回定位点
有时候划太远了,可能会找不到自己在哪。因此新增一个按钮,点击就让地图中心点回到定位点。
添加按钮
在activity_main.xml中添加一个按钮控件
<Buttonandroid:id="@+id/but_Loc"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="回到定位点"android:layout_marginLeft="0dp"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintTop_toTopOf="parent"android:layout_marginTop="127dp"/>
实现按钮
在public class MainActivity extends AppCompatActivity
后加上implements View.OnClickListener
实现按钮功能
//按钮响应private void button() {//按钮Button mbut_Loc = (Button) findViewById(R.id.but_Loc);//按钮处理mbut_Loc.setOnClickListener(this);}//回到定位点private void centerToMyLocation() {LatLng latLng = new LatLng(Latitude, Longitude);MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(latLng);mBaiduMap.animateMapStatus(update);}@Overridepublic void onClick(View v) {SDKInitializer.initialize(getApplicationContext());switch (v.getId()) {case R.id.but_Loc: {centerToMyLocation();break;}}}
最后在initmap()的最后加上一句button();
,这样点击按钮就能回到定位点了。
定位点模式切换
添加单选框
在activity_main.xml中添加RadioGroup
<RadioGroupandroid:id="@+id/Mode"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"android:background="#000000"app:layout_constraintStart_toStartOf="@+id/bmapView"app:layout_constraintTop_toTopOf="@+id/bmapView"><RadioButtonandroid:id="@+id/following"android:layout_width="137dp"android:layout_height="wrap_content"android:text="跟随态" /><RadioButtonandroid:id="@+id/normal"android:layout_width="137dp"android:layout_height="wrap_content"android:text="普通态"android:checked="true"/><RadioButtonandroid:id="@+id/compass"android:layout_width="137dp"android:layout_height="wrap_content"android:text="罗盘态" /></RadioGroup>
实现功能
添加新对象
//定位模式private RadioGroup mode;
初始化函数
public void initRadioGroup() {//获取radiongroup对象mode = (RadioGroup) findViewById(R.id.Mode);//通过radiogroup的setoncheckedlistener方法注册监听事件//在监听事件中创建oncheckedlistener 在重写oncheckedchanged方法mode.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(RadioGroup group, int checkedId) {//获取被选中的radiobutton的idRadioButton rcheck = (RadioButton) findViewById(checkedId);//获取String checkText = rcheck.getText().toString();MyLocationConfiguration configuration= null;switch (checkText){case "跟随态":configuration = new MyLocationConfiguration(MyLocationConfiguration.LocationMode.FOLLOWING,true, null );mBaiduMap.setMyLocationConfiguration(configuration);//罗盘态会改变百度地图的旋转和俯视角度,切换到其他模式需要重置mBaiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(new MapStatus.Builder(mBaiduMap.getMapStatus()).rotate(0).build()));mBaiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(new MapStatus.Builder(mBaiduMap.getMapStatus()).overlook(0).build()));break;case "普通态":configuration = new MyLocationConfiguration(MyLocationConfiguration.LocationMode.NORMAL,true, null );mBaiduMap.setMyLocationConfiguration(configuration);mBaiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(new MapStatus.Builder(mBaiduMap.getMapStatus()).rotate(0).build()));mBaiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(new MapStatus.Builder(mBaiduMap.getMapStatus()).overlook(0).build()));break;case "罗盘态":configuration = new MyLocationConfiguration(PASS,true, null );mBaiduMap.setMyLocationConfiguration(configuration);break;}}});}
在onCreate()的setContentView(R.layout.activity_main);
后添加initRadioGroup();
测试
可以流畅运行了。
源码
最后附上源代码
import androidx.annotation.NonNull;import androidx.appcompat.app.AppCompatActivity;import androidx.core.app.ActivityCompat;import android.Manifest;import android.content.pm.PackageManager;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.RadioButton;import android.widget.RadioGroup;import android.widget.Toast;import com.baidu.location.BDAbstractLocationListener;import com.baidu.location.BDLocation;import com.baidu.location.LocationClient;import com.baidu.location.LocationClientOption;import com.baidu.mapapi.CoordType;import com.baidu.mapapi.SDKInitializer;import com.baidu.mapapi.map.BaiduMap;import com.baidu.mapapi.map.MapStatus;import com.baidu.mapapi.map.MapStatusUpdate;import com.baidu.mapapi.map.MapStatusUpdateFactory;import com.baidu.mapapi.map.MapView;import com.baidu.mapapi.map.MyLocationConfiguration;import com.baidu.mapapi.map.MyLocationData;import com.baidu.mapapi.model.LatLng;public class MainActivity extends AppCompatActivity implements View.OnClickListener{private MapView mMapView = null;private BaiduMap mBaiduMap = null;private LocationClient mLocationClient = null;//方向传感器private MyOrientationListener mMyOrientationListener;private float mCurrentX;private double Latitude;private double Longitude;private float Radius;//是否为初次定位private boolean isFirst = true;//定位模式private RadioGroup mode;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//检查权限if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);}else if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.WRITE_EXTERNAL_STORAGE}, 2);}else if(ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.WRITE_EXTERNAL_STORAGE}, 3);} else {initSDK(true);setContentView(R.layout.activity_main);initRadioGroup();try {initmap();} catch (Exception e) {e.printStackTrace();}}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {switch (requestCode) {case 1:if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {Toast.makeText(this, "没有ACCESS_FINE_LOCATION权限!", Toast.LENGTH_LONG).show();finish();}break;case 2:if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {Toast.makeText(this, "没有ACCESS_COARSE_LOCATION权限!", Toast.LENGTH_LONG).show();finish();}break;case 3:if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {Toast.makeText(this, "没有WRITE_EXTERNAL_STORAGE权限!", Toast.LENGTH_LONG).show();finish();}break;}initSDK(true);setContentView(R.layout.activity_main);initRadioGroup();try {initmap();} catch (Exception e) {e.printStackTrace();}}private void initSDK(boolean status) {LocationClient.setAgreePrivacy(status);SDKInitializer.setAgreePrivacy(getApplicationContext(), status);try {//在使用SDK各组件之前初始化context信息,传入ApplicationContextSDKInitializer.initialize(getApplicationContext());//自4.3.0起,百度地图SDK所有接口均支持百度坐标和国测局坐标,用此方法设置您使用的坐标类型.//包括BD09LL和GCJ02两种坐标,默认是BD09LL坐标。SDKInitializer.setCoordType(CoordType.BD09LL);} catch (Exception e) {e.printStackTrace();}}private void initmap() throws Exception {//定位初始化mLocationClient = new LocationClient(getApplicationContext());mLocationClient.registerLocationListener(new MyLocationListener());//获取地图控件引用mMapView = (MapView) findViewById(R.id.bmapView);mBaiduMap = mMapView.getMap();mBaiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(new MapStatus.Builder().zoom(20).build()));//开启地图的定位图层mBaiduMap.setMyLocationEnabled(true);//通过LocationClientOption设置LocationClient相关参数LocationClientOption option = new LocationClientOption();option.setOpenGps(true); // 打开gpsoption.setCoorType("bd09ll"); // 设置坐标类型option.setIsNeedAddress(true);//设置是否需要地址信息option.setScanSpan(1000);//设置locationClientOptionmLocationClient.setLocOption(option);//注册LocationListener监听器MyLocationListener myLocationListener = new MyLocationListener();mLocationClient.registerLocationListener(myLocationListener);//注册监听函数initOrientation();//开启地图定位图层mLocationClient.start();button();}@Overrideprotected void onResume() {super.onResume();//在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理mMapView.onResume();}@Overrideprotected void onPause() {super.onPause();//在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理mMapView.onPause();}@Overrideprotected void onDestroy() {mLocationClient.stop();mBaiduMap.setMyLocationEnabled(false);mMapView = null;super.onDestroy();//在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理mMapView.onDestroy();}protected void onStart() {super.onStart();//开启定位mBaiduMap.setMyLocationEnabled(true);if (!mLocationClient.isStarted())mLocationClient.start();//开启方向传感器mMyOrientationListener.start();}@Overrideprotected void onStop() {super.onStop();//停止定位mBaiduMap.setMyLocationEnabled(false);mLocationClient.stop();//停止方向传感器mMyOrientationListener.stop();}//构造地图数据public class MyLocationListener extends BDAbstractLocationListener {@Overridepublic void onReceiveLocation(BDLocation location) {//mapView 销毁后不在处理新接收的位置if (location == null || mMapView == null){return;}Latitude=location.getLatitude();Longitude=location.getLongitude();Radius=location.getRadius();if(isFirst){LatLng latLng = new LatLng(Latitude, Longitude);MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(latLng);mBaiduMap.animateMapStatus(update);MyLocationConfiguration configuration = new MyLocationConfiguration(MyLocationConfiguration.LocationMode.NORMAL,true, null );mBaiduMap.setMyLocationConfiguration(configuration);isFirst=false;}MyLocationData locData = new MyLocationData.Builder().accuracy(Radius)// 此处设置开发者获取到的方向信息,顺时针0-360.direction(mCurrentX).latitude(Latitude).longitude(Longitude).build();mBaiduMap.setMyLocationData(locData);}}//传感器private void initOrientation() {//传感器mMyOrientationListener = new MyOrientationListener(getApplicationContext());mMyOrientationListener.setOnOrientationListener(new MyOrientationListener.OnOrientationListener() {@Overridepublic void onOrientationChanged(float x) {mCurrentX = x;MyLocationData locData = new MyLocationData.Builder().accuracy(Radius)// 此处设置开发者获取到的方向信息,顺时针0-360.direction(mCurrentX).latitude(Latitude).longitude(Longitude).build();mBaiduMap.setMyLocationData(locData);}});}//按钮响应private void button() {//按钮Button mbut_Loc = (Button) findViewById(R.id.but_Loc);//按钮处理mbut_Loc.setOnClickListener(this);}//回到定位点private void centerToMyLocation() {LatLng latLng = new LatLng(Latitude, Longitude);MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(latLng);mBaiduMap.animateMapStatus(update);}@Overridepublic void onClick(View v) {SDKInitializer.initialize(getApplicationContext());switch (v.getId()) {case R.id.but_Loc: {centerToMyLocation();break;}}}public void initRadioGroup() {//获取radiongroup对象mode = (RadioGroup) findViewById(R.id.Mode);//通过radiogroup的setoncheckedlistener方法注册监听事件//在监听事件中创建oncheckedlistener 在重写oncheckedchanged方法mode.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(RadioGroup group, int checkedId) {//获取被选中的radiobutton的idRadioButton rcheck = (RadioButton) findViewById(checkedId);//获取String checkText = rcheck.getText().toString();MyLocationConfiguration configuration= null;switch (checkText){case "跟随态":configuration = new MyLocationConfiguration(MyLocationConfiguration.LocationMode.FOLLOWING,true, null );mBaiduMap.setMyLocationConfiguration(configuration);//罗盘态会改变百度地图的旋转和俯视角度,切换到其他模式需要重置mBaiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(new MapStatus.Builder(mBaiduMap.getMapStatus()).rotate(0).build()));mBaiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(new MapStatus.Builder(mBaiduMap.getMapStatus()).overlook(0).build()));break;case "普通态":configuration = new MyLocationConfiguration(MyLocationConfiguration.LocationMode.NORMAL,true, null );mBaiduMap.setMyLocationConfiguration(configuration);mBaiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(new MapStatus.Builder(mBaiduMap.getMapStatus()).rotate(0).build()));mBaiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(new MapStatus.Builder(mBaiduMap.getMapStatus()).overlook(0).build()));break;case "罗盘态":configuration = new MyLocationConfiguration(PASS,true, null );mBaiduMap.setMyLocationConfiguration(configuration);break;}}});}}
完整项目
提取码:go1j
如果觉得《Android Studio3.0对于百度地图SDK的开发(基于方向传感器实现手机朝向显示)》对你有帮助,请点赞、收藏,并留下你的观点哦!