第十一章主要讲了 Android 特色功能,基于位置服务
一、基于位置的服务简介
基于位置的服务简称 LBS,主要工作原理是利用无线电通讯网络或GPS 定位方式来确定出移动设备所在的位置。要确定位置,通常有两种方式可以实现:
- 一种是通过 GPS 定位:GPS 定位的工作原理是基于手机内置的 GPS 硬件直接和卫星交互来获取当前的经纬度信息,这种定位方式精确度非常高,但是缺点是只能在室外使用,室内基本无法接收到卫星的信号。
- 一种是通过网络定位:网络定位的工作原理是根据手机当前网络附近的三个基站进行测速,计算出手机和每个基站之间的距离,再通过三角定位确定出一个大概位置,这种定位方式精确度一般,但优点是在室内外都可以使用。
Android 对这两种定位方式都提供相应的 API 支持,但是由于一些特殊原因,Google 的网络服务在中国不可访问,从而导致网络定位方式的 API 失效。而 GPS 定位虽然不需要网络,但是必须要在室外才可以使用,因此在室内开发的时候很有可能遇到不管使用哪种定位方式都无法成功定位的情况。
二、百度 SDK 准备工作
要使用百度 SDK,先要去申请 API Key,在申请 API Key 的时候需要填写发布版SHA1 和开发版 SHA1,这个指的是打包时所需的签名文件 SHA1指纹,可以通过 AndroidStudio 查看
注意:目前我们使用的是 debug.keystore 文件所生成的指纹,这是 Android 自动生成的一个用于测试的签名文件。而当你的应用程序发布时还需要创建一个正式的签名文件,如果要得到它的指纹,可以在 cmd 中输入如下命令:
keytool -list -v -keystore <签名文件路径>
,然后输入正确的密码就可以了
三、百度 SDK 的使用
我们需要将百度 LBS开放平台的 SDK准备好,可以选择你需要的功能并下载相应的 SDK,下载后解压压缩包,其中有一个 libs 目录,该目录下的内容分为两部分:BaiduLBS_Android.jar 和 其他子目录下的 so 文件,其中.jar 文件是 Java 层要用到的,so 文件是 Native 层要用到的。
该文件夹下放 Jar 包,然后在 main 目录下创建 jniLibs 文件夹。
然后将 so 文件夹及其子文件放到该文件夹中。
最后别忘了把我们添加的 jar 包引入到我们的项目中,Sync 一下 gradle 文件即可。
接下来就需要配置一些清单文件中的信息了,根据百度 SDK 的开发文档,在清单文件中写上需要申请的权限,然后在<application>标签内添加一个<meta-data>标签,该标签的 android:name 部分是固定的,必须填 com.baidu.lbsai.API_KEY,android:value 部分是申请的 API Key,最后还有注册一个 LBS SDK中的服务,具体详细的配置,开发文档中也有。
List<String> permissionList = new ArrayList<>();
if (ContextCompat.checkSelfPermission(DownloadActivity.this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if (ContextCompat.checkSelfPermission(DownloadActivity.this, Manifest.permission.READ_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.READ_PHONE_STATE);
}
if (ContextCompat.checkSelfPermission(DownloadActivity.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(this,permissions,1);
}else {
//TODO 已经获得了相应的权限
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
if (grantResults.length > 0) {
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "必须同意所有权限才能使用", Toast.LENGTH_SHORT).show();
finish();
return;
}
}
//TODO 用户已经全部同意了权限
} else {
Toast.makeText(this, "发生未知错误", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}
上述代码是一次性申请多个权限,记住,如果某些权限在同一组,只需要申请其一就可以了。首先创建了一个 List集合,然后依次判断权限是否被授权,如果没有被授权就添加到 List 集合中,然后将 List 转换成数组,在调用 ActivityCompat.requestPermissions()方法一次性申请。除此之外,onRequestPermissionResult()方法中对权限申请结果的处理也和之前有所不同,我们通过了一个循环将申请的每个权限都进行了判断,如果有任何一个权限被拒绝,那么就直接 finish 掉关闭当前程序,只有当所有权限都被用户同意了,才会继续。
获取经纬度
言归正传,要获取自己当前位置的经纬度,需要先获取 LocationClient 对象(构造方法传入 getApplicationContet()),然后设置监听,最后调用 start()方法开启定位。但是默认的只会定位一次,如果需要多次定位,需要借助 LocationClientOption 对象的 setScanSpan(5000)方法,这里表示每5秒更新一下当前位置,最后记住要在活动被销毁的时候一定要调用 locationClient 的 stop()方法来停止定位,否则程序会持续在后台不停地进行定位,会严重地消耗手机的电量。
设置定位模式
百度 LBS 的 SDK 中的定位模式一共有三种:Hight_Accuracy、Battery_Saving 和 Device_Se nsors。
- Hight_Accuracy:默认的模式,高精确度模式会在 GPS 新号正常的情况下优先使用 GPS 定位,在无法接收 GPS 信号的时候使用网络定位
- Battery_Saving:省电模式,只会使用网络进行定位。
- Device_Sensors:传感器模式,只会使用 GPS 进行定位
获取看得懂的位置信息
通过 LocationClientOption 的 setIsNeedAddress(true);方法可以获取更详细的地址信息,然后从 BDLocation 中通过 getCountry()和 getProvince()以及 getCity()等方法分别获取国家、省份等信息。
显示地图
要是想让地图显示出来,我们需要在布局文件中添加<com.baidu.mapapi.map.MapView>控件即可,然后在 onCreate 方法中添加代码SDKInitializer.initialize(getApplicationContext);
注意该方法必须要在 setContentView()之前调用,否则就会出错。然后在 onResume()和 onPause,onDestroy()方法中分别调用 mapView.onResume(),mapView.onPause(),mapView.onDestroy()......等方法同步生命周期。
BaiduMap 类
BaiduMap 类是地图的总控制器,调用 MapView.getMap()方法就能获取到 BaiduMap 的实例了。
- 百度地图将缩放级别的取值范围限定在3-19之间,而且小数点位的值也是可以取的。值越大,地图显示的信息就越精细。
- 借助 LatLng 类可以让地图移动到指定的经纬度上
需要注意的是:我们可能需要使用一个boolean 变量比如 isFirstLocate 来防止多次调用 animateMapStatus()方法,因为将地图移动到指定的位置只需要在程序第一次定位的时候调用一次就可以了。
还有其他的方法可以看百度开发文档,这里就不说了。