第十一章:Android特色服务—基于位置的服务

      移动设备相比于PC更容易携带,通过地理定位技术随时得知自己所在的位置。本章主要介绍了基于位置服务的简介(GPS定位和网络定位,百度和高德提供API)、申请百度API Key,使用百度定位确定经纬度、省市县街道、使用百度地图在地图上显示你的位置,最后是Git部分,概述了版本控制,介绍了分支的用法(更改修改查看合并等)、与远程版本库合作(介绍的比较理论,后面会有实践)。这一章内容比较少。

11.1 基于位置的服务简介

        LBS主要工作原理是利用无线电通讯网络或GPS等定位方式确定设备所在位置。Eg:微博晒自己在那里,天气预报选择城市。

实现当时主要有两种技术方式,一种是通过GPS定位,另一种是通过网络定位。GPS定位原理是通过GPS硬件与卫星交互。但缺点是只能在室外使用;网络定位是通过手机附近三个基站进行测速,以此计算距离确定位置。精度一般,但室内外通用。Google网络服务不可用,GPS必须室外才能用,因此,我们介绍第三方公司SDK。百度和高德在国内做的好,因此我们学习百度的LBS服务。

11.2申请API Key

        1.百度地图开放平台网址如下,随后填写注册信息,在自己的邮箱中完成验证,点击链接即可完成注册:http://lbsyun.baidu.com/index.php?title=%E9%A6%96%E9%A1%B5

        2.接着访问:http://lbsyun.baidu.com/apiconsole/key,创建移动应用去申请API Key,应用类型选择Android SDK,SHA1是应用程序打包程序是所用签名文件的指纹信息,申请API Key必须字段,在右侧点击Gradle->项目名->.app->Tasks->android->signingReport,此时可以看到:

《第一行代码》总结之Baidu SDK(六)_百度地图

《第一行代码》总结之Baidu SDK(六)_git_02

          3.申请完毕就如下图所示。应用的APIkey为:prOGOxSbMXXNQmdG8QQUAkTBIpKeCDLI

《第一行代码》总结之Baidu SDK(六)_LBS_03

11.3 使用百度定位
(一)准备LBS SDK。

          下载地址:

http://lbsyun.baidu.com/index.php?title=sdk/download&action#selected=mapsdk_basicmap,mapsdk_searchfunction,mapsdk_lbscloudsearch,mapsdk_calculationtool,mapsdk_radar

  勾选:室内定位和基础地图,下载之后将其文件放在libs和jnilibs目录下。然后点击Sync Now,这是Jar包就会被引用了。

《第一行代码》总结之Baidu SDK(六)_git_04《第一行代码》总结之Baidu SDK(六)_第一行代码_05

(二)确定自己的经纬度信息

        1.添加了许多权限声明,在application标签中添加meta-data标签。最后添加服务。权限包括了:《第一行代码》总结之Baidu SDK(六)_LBS_06

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="prOGOxSbMXXNQmdG8QQUAkTBIpKeCDLI" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote" />
</application>

       2.在OnCreate方法中,创建LocationClient的实例,其构建函数接受一个Context参数,这里调用LocationClient的registerLocationListener方法来注册监听器,当获取到位置信息时,回调此定位监听器。在这里有四个危险权限:ACCESS_FINE_LOCATION、READ_PHONE_STATE、ACCESS_COARSE_LOCATION、WRITE_EXTERNAL_STORAGE。但因为两个Location属于同组,所以申请其一即可,这里有一个小技巧:一次性申请三个权限,判断是否授权,若未授权,则将List集合转为数组,在调用ActivityCompat.requestPermissions来一次性申请。此时onRequestPermissionsResult方法通过循环对申请的每个权限进行判断,若有一个被拒绝,则调用finish方法。

       3.requestLocation方法使用mlocationClient.start();进行定位。定位结果会返回知刚才定义的监听器。getLatitude获取经度getLongitude获取纬度bdLocation.getLocType()获取定位类型。

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mlocationClient = new LocationClient(getApplicationContext());
mlocationClient.registerLocationListener(new MyLocationListener());
tv_position01 = (TextView) findViewById(R.id.tv_position);
List<String> permissionList = new ArrayList<>();
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.READ_PHONE_STATE);
}
if (ContextCompat.checkSelfPermission(MainActivity.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(MainActivity.this, permissions, 1);
} else {
requestLocation();
}
}

private void requestLocation() {
mlocationClient.start();
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] 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;
}
requestLocation();
}
}else{
Toast.makeText(this,"发生未知错误",Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
break;
}
}
public class MyLocationListener implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation bdLocation) {
StringBuilder currentposition = new StringBuilder();
currentposition.append("纬度:").append(bdLocation.getLatitude()).append("\n");
currentposition.append("经度:").append(bdLocation.getLongitude()).append("\n");
currentposition.append("定位方式:");
if(bdLocation.getLocType()== BDLocation.TypeGpsLocation){
currentposition.append("GPS");
}else if(bdLocation.getLocType() == BDLocation.TypeNetWorkLocation){
currentposition.append("网络");
}
tv_position01.setText(currentposition.toString());
}
}

        4.调用LocationClient的start只会调用一次,若快速移动,则使用LocationClientOption的setScanSpan方法来设置间隔,五秒更新一次,最后将配置设置进去。最后活动被销毁时使用mlocationClient.stop();方法停止定位,否则一直定位,严重耗电。

private void requestLocation() {
initLocation();
mlocationClient.start();
}

private void initLocation() {
LocationClientOption option = new LocationClientOption();
option.setScanSpan(5000);
mlocationClient.setLocOption(option);
}

@Override
protected void onDestroy() {
super.onDestroy();
mlocationClient.stop();
}

 (三)设置定位方式

        高精确度模式:使用GPS、无线、蓝牙或移动网络定位,节电模式允许使用除GPS之外的,设备模式仅允许使用GPS定位。因此一共三种模式:high_Accuracy、Battery_Accuracy和Device_Sensors,对应三种模式。在这里我们强制使用GPS模式定位。

private void initLocation() {
LocationClientOption option = new LocationClientOption();
option.setScanSpan(5000);
option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);
mlocationClient.setLocOption(option);
}

(四)看的懂的地理信息

option.setIsNeedAddress(true);
currentposition.append("国家:").append(bdLocation.getCountry()).append("\n");
currentposition.append("省:").append(bdLocation.getProvince()).append("\n");
currentposition.append("市:").append(bdLocation.getCity()).append("\n");
currentposition.append("区:").append(bdLocation.getDistrict()).append("\n");
currentposition.append("街道:").append(bdLocation.getStreet()).append("\n");

        注意,因为获取地址信息肯定会用到网络,因此即使将定位模式设置为Device_Sensors,也会自动开启网络定位功能。

11.4 使用百度地图
11.4.1 让地图显示出来

        1.布局文件中防止MApView的控件,使其布满屏幕,之前TextView暂时用不到,设置为gone属性。

<com.baidu.mapapi.map.MapView
android:id="@+id/bmapview"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:clickable="true"/>

        2.首先需要调用SDKInitializer.initialize(getApplicationContext());来初始化。初始化操作必须要在setContentView之前调用。不然就会出错。接着重写onResume、onDestroy和onPause三个方法,确保资源能够及时得到释放。

@Override
protected void onDestroy() {
super.onDestroy();
mlocationClient.stop();
mapView.onDestroy();
}

@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}

@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}

11.4.2 移动到我的位置
      如何才能快速找到自己的位置呢?

      1.百度LBS SDK的API提供了BaiduMap类,它是地图总控制器,调用MapView的getMap方法即可获的BaiduMap实例。设置缩放级别有zoomTo的API,若需要移动位置,则借助于LatLng类,用于存放经纬度,调用MapStatusUpdateFactory.newLatLng(ll);将Latlng传入。其返回的是一个MapStatusUpdate对象,最后将这个对象通过baiduMap.animateMapStatus(update);移动到指定的经纬度上。

baiduMap = mapView.getMap();

private void navigateTo(BDLocation bdLocation) {
if(isFisrstLocate){
LatLng ll = new LatLng(bdLocation.getLatitude(),bdLocation.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
baiduMap.animateMapStatus(update);
update = MapStatusUpdateFactory.zoomTo(16f);
baiduMap.animateMapStatus(update);
isFisrstLocate=false;
}
}

public class MyLocationListener implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation bdLocation) {
if(bdLocation.getLocType()== BDLocation.TypeGpsLocation|| bdLocation.getLocType() == BDLocation.TypeNetWorkLocation){
navigateTo(bdLocation);
}
}}

11.4.3 让我显示在地图上。

       1.MyLocationData.Builder用于封装设备当前位置,将经纬度信息传入到这个类中的响应方法即可。

       2.MyLocationData.Builder还提供了build方法,生成MyLocationData实例,然后再将这个实例通过 baiduMap.setMyLocationData(locationData);传入到baiduMap中去。这样就可以像是设备的位置了。

       3.由于百度地图显示,开始调用之前,一定要通过baiduMap.setMyLocationEnabled(true);开启此功能。最后在onDestroy中关闭掉。

private void navigateTo(BDLocation bdLocation) {
if(isFisrstLocate){
LatLng ll = new LatLng(bdLocation.getLatitude(),bdLocation.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
baiduMap.animateMapStatus(update);
update = MapStatusUpdateFactory.zoomTo(16f);
baiduMap.animateMapStatus(update);
isFisrstLocate=false;
}
MyLocationData.Builder locationbuilder = new MyLocationData.Builder();
locationbuilder.latitude(bdLocation.getLatitude());
locationbuilder.longitude(bdLocation.getLongitude());
MyLocationData locationData = locationbuilder.build();
baiduMap.setMyLocationData(locationData);
}

11.5 Git时间——版本控制工具的高阶用法

         完成准备工作: 

git init
git add .
git commit -m “First Commit”

(一)分支的用法

        分支的作用是在现有代码基础之上开辟一条分叉口,使得代码可以在主干线和分支线上同时开发,相互不影响。

应用场景:开发了1.0版本后开始开发1.1版本,这时已上线的1.0出现重大bug严重影响使用。于是去修复1.0的bug。但此时1.1已经开发一半,若在此基础之上修复bug,则更新的1.0会带有一半的1.1版本的功能。解决方法:在1.0版本发布时建立分支,在主干线上继续开发1.1的功能,当1.0发现bug时,则修改分支线,将修改后的代码合并到主干线上。这样解决了bug,主干线的代码也完成了修复,不影响1.1的开发。

《第一行代码》总结之Baidu SDK(六)_第一行代码_07

1.检查当前版本库中有哪些分支

git branch

《第一行代码》总结之Baidu SDK(六)_第一行代码_08

2.建立分支,但此时我们的代码仍在master分支

git branch version1.0

《第一行代码》总结之Baidu SDK(六)_第一行代码_09

3.如何将代码切换至version1.0分支,随后进行检查。

git checkout version1.0
git branch

《第一行代码》总结之Baidu SDK(六)_位置定位_10

       这时在1.0分支上提交的代码不影响master分支。此时修复1.0上的bug,masteer的bug依然存在,手动复制显然麻烦,最好的办法就是merge命令去做。

4.合并分支,首先切换分支到master,在合并version1.0的分支到master,也有代码冲突情况,需要静下心来去找。

git checkout master
git merge version1.0

《第一行代码》总结之Baidu SDK(六)_第一行代码_11

5.不需要version1.0分支时,删除它。

git branch -D version1.0

《第一行代码》总结之Baidu SDK(六)_第一行代码_12

(二)与远程版本库协作。

        版本控制工具最主要特定就是团队合作开发。不是一个人玩。

1.创建git仓库,地址为:https://github.com/hzka/testing.git,将其下载到本地。

git clone https://github.com/hzka/testing.git

《第一行代码》总结之Baidu SDK(六)_第一行代码_13

2.将本地修改内容同步至远程.origin是远程仓库git地址,master是同步到哪一个分支。这就同步到了master的分支了。

git push origin master

3.将远程修改同步到本地,git提供了fetch和pull。其存放在origin/mater分支下。

git fetch origin master

3.查看远程版本库修改了哪些。和本地不一样的地方。

git diff origin/master

4.调用merge进行将origin/mater分支合并至本地主分支。

git merge origin/master

5.而pull命令是将fetch和merge一起执行了。

git pull origin master

          有点抽象是吗?14章将会对第二部分进行实践,很简单的哈哈。