文章目录
前言
上午刚说不知道怎么绑定方向传感器,下午就找到教程了……
主要参考了花海ipa大大的这篇文章
2019-详细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);
}
@Override
public void onAccuracyChanged(Sensor arg0, int arg1)
{
// TODO Auto-generated method stub
}
@SuppressWarnings(
{ "deprecation" })
@Override
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 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() {
@Override
public 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); // 打开gps
option.setCoorType("bd09ll"); // 设置坐标类型
option.setIsNeedAddress(true);//设置是否需要地址信息
option.setScanSpan(1000);
//设置locationClientOption
mLocationClient.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();
}
@Override
protected 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() {
@Override
public 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中添加一个按钮控件
<Button
android: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);
}
@Override
public void onClick(View v) {
SDKInitializer.initialize(getApplicationContext());
switch (v.getId()) {
case R.id.but_Loc: {
centerToMyLocation();
break;
}
}
}
最后在initmap()的最后加上一句button();
,这样点击按钮就能回到定位点了。
定位点模式切换
添加单选框
在activity_main.xml中添加RadioGroup
<RadioGroup
android: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">
<RadioButton
android:id="@+id/following"
android:layout_width="137dp"
android:layout_height="wrap_content"
android:text="跟随态" />
<RadioButton
android:id="@+id/normal"
android:layout_width="137dp"
android:layout_height="wrap_content"
android:text="普通态"
android:checked="true"/>
<RadioButton
android: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() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
//获取被选中的radiobutton的id
RadioButton 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(MyLocationConfiguration.LocationMode.COMPASS,
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;
@Override
protected 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();
}
}
}
@Override
public 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信息,传入ApplicationContext
SDKInitializer.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); // 打开gps
option.setCoorType("bd09ll"); // 设置坐标类型
option.setIsNeedAddress(true);//设置是否需要地址信息
option.setScanSpan(1000);
//设置locationClientOption
mLocationClient.setLocOption(option);
//注册LocationListener监听器
MyLocationListener myLocationListener = new MyLocationListener();
mLocationClient.registerLocationListener(myLocationListener);
//注册监听函数
initOrientation();
//开启地图定位图层
mLocationClient.start();
button();
}
@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() {
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();
}
@Override
protected void onStop() {
super.onStop();
//停止定位
mBaiduMap.setMyLocationEnabled(false);
mLocationClient.stop();
//停止方向传感器
mMyOrientationListener.stop();
}
//构造地图数据
public class MyLocationListener extends BDAbstractLocationListener {
@Override
public 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() {
@Override
public 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);
}
@Override
public 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() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
//获取被选中的radiobutton的id
RadioButton 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(MyLocationConfiguration.LocationMode.COMPASS,
true, null );
mBaiduMap.setMyLocationConfiguration(configuration);
break;
}
}
});
}
}
完整项目
提取码:go1j