基于位置的服务简称 LBS(Location Based Service),它是利用无线电通信网络或 GPS 定位方式来肯定出移动设备所在的位置。android
利用定位服务,能够开发出许多丰富多彩的功能。好比天气预报 APP,能够根据用户所在的位置自动选择所在城市。约会时,能够经过微信发出碰头地点,让朋友们可以尽快过来等等。git
肯定出用户所在的位置。一般有两种技术:api
技术 | 说明 | 优势 | 不足 |
---|---|---|---|
GPS 定位 | 它是基于手机内置的 GPS 硬件直接和卫星交互来得到当前的经纬度信息。 | 精确度高 | 只能室外使用,由于室内基本没法接收到卫星的信号。 |
网络定位 | 根据手机当前网络附近的三个基站进行测速,以此计算出手机和每一个基站之间的距离,最后经过三角定位肯定一个大概位置。 | 室内外都可使用。 | 精确度通常。 |
首先必须先注册一个百度开发者帐号(官网请点击),这个很简单,因此这里就不赘述了哦O(∩_∩)O哈哈~数组
注册并登录成功后,打开百度地图开放平台建立新应用:安全
点击 Android Studio 的 Gradle 标签,执行 signingReport 任务。bash
执行成功后,点击右下角的【Gradle Console】标签,能够看到生成的 SHA1 码:微信
点击【提交】成功后,就会转到应用列表页,里面的访问应用(AK)就是咱们申请到的 API Key 啦:网络
建议在手机上运行下面的代码,由于这样能够获得真实的位置数据,有助于咱们更深入地理解基于位置的服务。app
打开百度地图开放平台,找到地图引擎入口:ide
点击后,进入地图 SDK 说明页:
点击产品下载-》自定义下载,在此选择相应的开发资源:
这里咱们选择【全量定位】与【基础地图】资源。
这里的 BaiduLBS_Android.jar 就是百度提供的 API 包。因此咱们把这个包放入 app 的 libs 目录下:
**注意:**若是找不到 libs 目录,一个可能的缘由是视图模式问题,视图模式(页签左上角)请选择【Project】。
接下来在 app → src → main 中,新建一个 jniLibs 文件夹,而后再把百度下载包中的其它文件夹都拷贝到这个新建的文件夹中:
由于是手动引入包,因此须要点击 Android Studio 工具栏中的 Sync Project with Gradle Files,手动同步:
同步成功后,就会发现刚才手工引入的 jar 包左侧多了一个朝右的箭头,这就表示这个包在项目中能够引用啦:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</LinearLayout>
复制代码
这里,咱们使用 TextView 来显示当前位置的经纬度。
...
<!--百度 LBS API 的相关权限声明-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<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="aYOacSei5VfK2eC7GjcS8j7iPGxGjPal" />
<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>
复制代码
在此,咱们作了如下工做:
<application>
标签内添加了 <meta-data>
标签,在此记录以前申请的百度 API Key。f
,是由于代码被混淆过。public class MainActivity extends AppCompatActivity {
public static final int REQUEST_CODE = 1;
public LocationClient locationClient;
private TextView position;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationClient = new LocationClient(getApplicationContext());
//注册【定位监听器】
locationClient.registerLocationListener(new LocationListener());
position = (TextView) findViewById(R.id.position);
/**
* 一次性申请多个权限
*/
List<String> permissions = new ArrayList<>();
addPermission(permissions, Manifest.permission.ACCESS_FINE_LOCATION);
addPermission(permissions, Manifest.permission.READ_PHONE_STATE);
addPermission(permissions, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (!permissions.isEmpty()) {
ActivityCompat.requestPermissions(MainActivity.this, permissions.toArray(new String[permissions.size()]), REQUEST_CODE);
} else {
beginLocation();
}
}
/**
* 开始定位
*/
private void beginLocation() {
setLocationOptions();
locationClient.start();
}
/**
* 设置 LBS
*/
private void setLocationOptions() {
LocationClientOption option = new LocationClientOption();
//每 10 s 更新一次当前位置
option.setScanSpan(10000);
locationClient.setLocOption(option);
}
@Override
protected void onDestroy() {
super.onDestroy();
locationClient.stop();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_CODE:
if (grantResults.length > 0) {
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "权限被拒绝啦", Toast.LENGTH_SHORT).show();
finish();
return;
}
}
beginLocation();
} else {
Toast.makeText(this, "出现与权限相关的问题啦", Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
break;
}
}
/**
* 添加权限
*
* @param permissions
* @param neededPermission 须要的权限
*/
private void addPermission(List<String> permissions, String neededPermission) {
if (ContextCompat.checkSelfPermission(MainActivity.this, neededPermission) != PackageManager.PERMISSION_GRANTED) {
permissions.add(neededPermission);
}
}
/**
* 定位监听器
*/
private class LocationListener implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation location) {
StringBuilder content = new StringBuilder();
content.append("纬度:").append(location.getLatitude() + "\n");
content.append("经度:").append(location.getLongitude() + "\n");
content.append("定位方式:");
if (location.getLocType() == BDLocation.TypeGpsLocation) {
content.append("GPS");
} else if (location.getLocType() == BDLocation.TypeNetWorkLocation) {
content.append("网络");
}
position.setText(content);
}
}
}
复制代码
在此,咱们作了如下工做:
List<String>
实现一次性申请多个权限,由于 ActivityCompat.requestPermissions()
接受数组参数,而 List 转为数组很容易。getLatitude()
表示获取经度,getLongitude()
表示获取纬度。getLocType()
表示获取定位的方式。locationClient.stop();
中止定位,不然 locationClient 会默默地在后台不停地进行定位工做,这会对手机电量产生严重影响。安装并运行 APP:
由于 GPS 定位须要手动开启,它通常在手机的设置 → 位置信息中。
若是是小米手机,那么它在 设置 → 更多设置 → 系统安全 → 位置信息中。
能够看出,定位模式有三种,上诉截图中对每一种定位模式都作了详细介绍。
在 LBS SDK 也有三种定位模式与手机的定位模式相匹配:
定位模式 | 说明 |
---|---|
Hight_Accuracy | 高精确度(默认模式),会在 GPS 信号正常的状况下优先使用 GPS 定位,在没法接收 GPS 信号时用网络定位 。 |
Battery_Saving | 节电,只会使用网络定位。 |
Device_Sensors | 设备传感器,只会使用GPS定位。 |
**注意:**只有当定位操做真正开始的时候,才会影响到手机的电量。
也能够经过 LocationClientOption 的 setLocationMode 方法来指定定位模式:
option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);
复制代码
经过 LocationClientOption 的 setIsNeedAddress 方法,能够开启地址信息获取功能:
option.setIsNeedAddress(true);
复制代码
而后就能够在 BDLocation 中获取到地址信息啦:
content.append("所在国家:").append(location.getCountry() + "\n");
content.append("所在省份:").append(location.getProvince() + "\n");
content.append("所在市:").append(location.getCity() + "\n");
content.append("所在区:").append(location.getDistrict() + "\n");
content.append("所在街道:").append(location.getStreet() + "\n");
复制代码
**注意:**获取地址必须使用网络哦O(∩_∩)O~
如今让咱们在 APP 中展现地图吧O(∩_∩)O~
修改布局文件,加入地图视图控件:
<com.baidu.mapapi.map.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true">
</com.baidu.mapapi.map.MapView>
复制代码
以前的 TextView 可使用 android:visibility="gone"
将其隐藏。
修改活动类:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/**
* 初始化地图
*/
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_main);
mapView = (MapView) findViewById(R.id.mapView);
...
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
locationClient.stop();
mapView.onDestroy();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
复制代码
在该类中,咱们新增了这些逻辑:
setContentView(R.layout.activity_main);
以前调用,不然会抛出 you have not supplyed the global app context info from SDKInitializer.initialize(Context) function
错误。百度 LBS SDK 的 API 中提供了一个BaiduMap 类,使用如下方法实例化后,就能够对地图进行各类各样的操做啦:
BaiduMap baiduMap = mapView.getMap();
复制代码
修改活动类:
...
private BaiduMap baiduMap;
//是否为第一次定位
private boolean isFirstLocated = true;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
baiduMap = mapView.getMap();
}
private class LocationListener implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation location) {
if (location.getLocType() == BDLocation.TypeGpsLocation || location.getLocType() == BDLocation.TypeNetWorkLocation) {
if (isFirstLocated) {
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
//设置经纬度
baiduMap.animateMapStatus(MapStatusUpdateFactory.newLatLng(latLng));
//设置缩放级别(在 3 ~ 19 之间)
baiduMap.animateMapStatus(MapStatusUpdateFactory.zoomTo(16f));
isFirstLocated = false;
}
}
}
}
复制代码
能够看出,经过 LatLng latLng = new LatLng(39.9, 116.3);
方法,就可让地图移动任何地址啦O(∩_∩)O~
运行程序:
地图上能够添加一个标注,用于显示当前位置。
百度 LBS SDK 提供了一个 MyLocationData.Builder
类,它封装了设备当前所在的位置,咱们只需将经纬度信息传入便可。
修改活动类:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
baiduMap.setMyLocationEnabled(true);
}
...
private class LocationListener implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation location) {
...
if (location.getLocType() == BDLocation.TypeGpsLocation || location.getLocType() == BDLocation.TypeNetWorkLocation) {
if (isFirstLocated) {
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
//设置经纬度
baiduMap.animateMapStatus(MapStatusUpdateFactory.newLatLng(latLng));
//设置缩放级别(在 3 ~ 19 之间)
baiduMap.animateMapStatus(MapStatusUpdateFactory.zoomTo(16f));
isFirstLocated = false;
}
//添加标注
MyLocationData.Builder builder = new MyLocationData.Builder();
builder.latitude(location.getLatitude());
builder.longitude(location.getLongitude());
baiduMap.setMyLocationData(builder.build());
}
}
@Override
protected void onDestroy() {
super.onDestroy();
locationClient.stop();
mapView.onDestroy();
baiduMap.setMyLocationEnabled(false);
}
复制代码
作了这些工做:
1.在 onCreate 方法中,开启标注。 2.在 LocationListener 的 onReceiveLocation 方法中添加标注。 3.在 onDestroy 方法中,关闭标注。
由于通常只需移动一次地图的中心位置,因此咱们在代码中加了 isFirstLocated 变量进行判断。
再次运行:
看见地图中心的蓝点了吗O(∩_∩)O哈哈~