2021@SDUSC
定位功能实现
private LocationClient mLocationClient = null;
private MyLocationConfiguration.LocationMode locationMode;
private MyLocationConfiguration.LocationMode mLocationMode;
首次,需要进行准备工作没配置好百度地图的Android定位SDK,在官方网站上按照教程获取密钥,在AndroidManifest.xml、主工程的build.gradle文件进行配置环境工作。 然后需要在主线程中声明LocationClient类对象,该对象初始化需传入Context类型参数。例如使用getApplicationConext()方法获取全进程有效的Context。 LocationClient 类是定位服务的客户端,宿主程序在客户端声明此类,并调用,目前只支持在主线程中启动。
public class MyLocationListener extends BDAbstractLocationListener {
@Override
public void onReceiveLocation(BDLocation location) {
//mapView 销毁后不在处理新接收的位置
if (location == null || mMapView == null){
return;
}
LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
if (isFirstLocate) {
isFirstLocate = false;
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
mBaiduMap.animateMapStatus(update);
update = MapStatusUpdateFactory.zoomTo(18f);
mBaiduMap.animateMapStatus(update);
}
MyLocationData locData = new MyLocationData.Builder()
.accuracy(location.getRadius())
.direction(location.getDirection()).latitude(location.getLatitude())
.longitude(location.getLongitude()).build();
mBaiduMap.setMyLocationData(locData);
}
}
Abstract类型的监听接口BDAbstractLocationListener,用于实现定位监听,该接口会异步获取定位结果。onReceiveLocation(BDLocation location)是定位请求回调函数。此处的BDLocation类为定位结果信息类,通过它的各种get方法可获取定位相关的全部结果。 LatLng类是地理坐标基本数据结构,location.getLatitude() 获取纬度坐标,location.getLongitude() 获取经度坐标。 作者设置了一个变量判断用户是否第一次定位,如果是先将isFirstLocate状态改为false,第一次执行后其余都不再是第一次, 然后设置地图的一些显示状态,如显示时以什么位置为中心,还有用户显示的缩放地图是以多少为基准。MapStatusUpdate类是描述地图状态将要发生的变化。 MapStatusUpdateFactory用于生成地图状态将要发生的变化。MapStatusUpdateFactory.newLatLng(ll); 是将当前获取得定位设置为地图的新中心点。mBaiduMap.animateMapStatus(update); 可以以动画方式更新刚刚定义的地图变化状态,即将地图改变为以用户当前定位为中心显示,默认动画耗时300ms。后面设置地图缩放级别,利用地图状态工厂类的方法zoomTo(18f) ,将update变量由设定中心位置改为按照方法给定数值18f设置地图缩放级别,然后再次更新地图mBaiduMap状态。 无论是否第一次定位都将执行的操作如下。MyLocationData是定位数据类,它可以包含定位精度(accuracy)、GPS定位时方向角度(direction)、百度纬度坐标(latitude)、百度经度坐标(longitude)、GPS定位时卫星数目(satellitesNum)和GPS定位时速度信息(speed)。MyLocationData.Builder是定位数据建造器,是MyLocationData的嵌套类,通过方法build() 可以为它构建生成定位数据对象。location.getRadius() 是获取当前定位的精度,默认值为0.0f。location.getDirection() 是获取GPS定位结果时,行进的方向,单位为度。这一句代码作者根据当前定位的精度通过定位数据建造器为新建的定位数据对象建造属性定位精度(accuracy)、GPS定位时方向角度(direction)、百度纬度坐标(latitude)、百度经度坐标(longitude)。最后setMyLocationData(locData) 设置上述定义好的定位数据对象,该方法只有先允许定位图层后设置数据才会生效。
点击屏幕下方位置简介按钮监听器
private Place_Info tech_info = new Place_Info(R.string.tech_name, R.string.tech_des, R.drawable.pic_tech);
private Place_Info library_info = new Place_Info(R.string.library_name, R.string.library_des, R.drawable.pic_library);
private Place_Info dining_info = new Place_Info(R.string.dining_name, R.string.dining_des, R.drawable.pic_dining);
public void onClick(View v){
if(v.getId() == R.id.btn_library){
mIntent = new Intent(MainActivity.this, DescriptionActivity.class);
//使用Bundle来传递Int类型的数据
Bundle bundle = new Bundle();
bundle.putInt("name", library_info.getName());
bundle.putInt("des",library_info.getDescreption());
bundle.putInt("picname", library_info.getPicname());
mIntent.putExtras(bundle);
startActivity(mIntent);
}else if(v.getId() == R.id.btn_tech){
mIntent = new Intent(MainActivity.this, DescriptionActivity.class);
Bundle bundle = new Bundle();
bundle.putInt("name", tech_info.getName());
bundle.putInt("des",tech_info.getDescreption());
bundle.putInt("picname", tech_info.getPicname());
mIntent.putExtras(bundle);
startActivity(mIntent);
}else if(v.getId() == R.id.btn_dining){
mIntent = new Intent(MainActivity.this, DescriptionActivity.class);
Bundle bundle = new Bundle();
bundle.putInt("name", dining_info.getName());
bundle.putInt("des",dining_info.getDescreption());
bundle.putInt("picname", dining_info.getPicname());
mIntent.putExtras(bundle);
startActivity(mIntent);
}
}
作者一共标记软件园三个位置图书馆、教学楼和食堂,通过按钮的id如R.id.btn_dining判断用户查询的是哪一个地址的详细信息。通过Intent进行由当前MainActivity切换到 DescriptionActivity,展示地址详细窗口。Bundle传递DescriptionActivity活动所需要显示的地址信息,下面这个类是作者所封装的地址信息类,包括地址名称、地点描述和图片,在该类里作者定义好了所需要的三个Place_Info 地址对象,然后根据R索引在String中找到对应信息放入Bundle对象中。mIntent.putExtras(bundle); 通过Intent将Bundle传到另一个DescriptionActivity中。startActivity(mIntent); 切换到新的Activity。
public class Place_Info {
private int name;//地名id
private int descreption;//地点描述id
private int picname;//图片id
}
权限声明
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case BAIDU_READ_PHONE_STATE:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
init();
} else {
Toast.makeText(getApplicationContext(), "获取位置权限失败,请手动开启", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}
onRequestPermissionsResult() 为运行时权限动态监测前,即有些权限需要在运行时判断,比如日历、摄像头、地理位置等,此类权限授予应用对受限数据的额外访问权限,并允许应用执行对系统和其他应用具有更严重影响的受限操作。Android中在应用程序需要用到权限是,会检查APP是否已经拥有权限,比如定位功能需要访问GPS定位,我们在写入之前检查是否有ACCESS_FINE_LOCATION权限,如果没有则申请权限。请求权限后,系统会弹出请求权限的Dialog。用户选择允许或者拒绝后,会回调onRequestPermissionsResult方法,根据requestCode和grantResults即授权结果做相应的后续处理。requestCode即所声明的权限获取码,在checkSelfPermission时传入。BAIDU_READ_PHONE_STATE 为可以获取手机状态权限,如果应用程序的权限获取码为此,就执行init() 初始化数据等操作。PackageManager.PERMISSION_GRANTED 为获得权限的表示。如果没有获取到会弹出提示框提示用户获取位置权限失败,请用户手动开启权限。
public void showContacts(){
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_PHONE_STATE}, BAIDU_READ_PHONE_STATE);
}else{
init();
}
}
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)检查应用程序是否有访问网络定位的权限,后面还判断用户是否有GPS定位权限和读取手机状态权限,该方法返回值PackageManager.PERMISSION_GRANTED表示有权限,PackageManager.PERMISSION_DENIED表示无权限。当应用需要用到危险权限时,在执行权限相关代码前,使用该方法判断是否拥有指定的权限。有权限,则继续执行设计需要权限的代码;无权限,则向用户请求授予权限。如果这三个权限中用户有一个没有的话,调用ActivityCompat.requestPermissions() 方法可以传入数组参数,当前Activity一次可以请求多个权限。传入的权限数组参数以单个具体权限为单位,但弹框询问用户授权时,属于同一权限组的权限将自动合并询问授权一次。请求的权限必须事先在 AndroidManifest.xml 中有声明,否则调用此方法请求时,将不弹框,而是直接返回“拒绝”的结果。第一次请求权限时,用户点击了“拒绝”,第二次再请求该权限时,对话框将出现“不再询问”复选框,如果用户勾选了“不再询问”并点击了“拒绝”,则之后再请求此权限组时将不弹框,而是直接返回“拒绝”的结果。如果用户有这三个权限,则初始化数据,显示地图和定位等信息。
|