本篇文章主要介紹以下幾個知識點:
- 百度定位。
- 百度地圖寂汇。
11.1 基于位置的服務(wù)簡介
基于位置的服務(wù)簡稱 LBS(Location Based Service),主要的工作原理是利用無線電通訊網(wǎng)絡(luò)或 GPS 等定位方式來確定出移動設(shè)備所在的位置梅割。
LBS 所圍繞的核心就是要確定出用戶所在的位置僚稿。通常有兩種技術(shù):
GPS 定位:
?基于手機內(nèi)置的 GPS 硬件直接和衛(wèi)星交互來獲取當前的經(jīng)緯度信息,精確度高丐怯,但只能室外使用喷好,室內(nèi)基本無法接收到衛(wèi)星的信號。網(wǎng)絡(luò)定位:
?根據(jù)手機當前網(wǎng)絡(luò)附近的三個基站進行測速读跷,以此計算出手機和每個基站之間的距離梗搅,再通過三角定位確定一個大概位置,精確度一般效览,但室內(nèi)外均可使用无切。
本章主要學習百度在 LBS 方面提供的一些功能。
11.2 使用百度定位
要想在自己的應(yīng)用程序里使用百度的 LBS 功能丐枉,首先必須申請一個 API Key哆键,有了 API Key 就可以進行后續(xù)的 LBS 開發(fā)工作了。
11.2.1 準備 LBS SDK
在編碼之前矛洞,先將百度 LBS 開放平臺的 SDK 準備好洼哎,下載地址:http://lbsyun.baidu.com/sdk/download
本章會用到基礎(chǔ)地圖和基礎(chǔ)定位這兩個 SDK烫映,下載完后對該壓縮包解壓,libs 目錄里就有我們所需要的一切了:
下面把 libs 目錄里的內(nèi)容拷貝到我們的項目中:
?(1)把 BaiduLBS_Android.jar 拷貝到項目 app 模塊中的 libs 目錄:
(2)展開 src/main 目錄噩峦,右擊該目錄→New→Directory锭沟,創(chuàng)建一個名為 jniLibs 的目錄,用來存放 so 包识补,然后把壓縮包里的其他所以目錄直接復(fù)制到這里:
另外族淮,記得點擊頂部工具欄中的 Sync 按鈕(下圖中最左邊的按鈕)將 BaiduLBS_Android.jar 添加到當前項目的引用中。
以上就把 LBS 的 SDK 都準備好了凭涂。
11.2.2 確定自己位置的經(jīng)緯度
首先在 AndroidManifest 中添加開發(fā)密鑰祝辣、所需權(quán)限等信息:
?(1)在 application 中添加開發(fā)密鑰
<application>
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="開發(fā)者 key" />
</application>
(2)添加所需權(quán)限
<!-- 百度 LBS 相關(guān)權(quán)限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<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" />
(3)再注冊一個百度 LBS SDK 中的服務(wù)
<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote">
</service>
接下來在布局添加個 TextView 來顯示當前位置的經(jīng)緯度:
public class LocationActivity extends AppCompatActivity {
private LocationClient mLocationClient;
private TextView tv_show_location;// 顯示當前位置信息
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 構(gòu)建 LocationClient 實例
mLocationClient = new LocationClient(getApplicationContext());
// 注冊一個定位監(jiān)聽器
mLocationClient.registerLocationListener(new MyLocationListener());
setContentView(R.layout.activity_location);
tv_show_location = (TextView) findViewById(R.id.tv_show_location);
// 聲明權(quán)限,將權(quán)限添加到list集合中再一次性申請
List<String> permissionList = new ArrayList<>();
if (ActivityCompat.checkSelfPermission(LocationActivity.this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if (ActivityCompat.checkSelfPermission(LocationActivity.this,
Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.READ_PHONE_STATE);
}
if (ActivityCompat.checkSelfPermission(LocationActivity.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(LocationActivity.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){
ToastUtils.showShort("必須同意所有權(quán)限才能使用本程序");
finish();
return;
}
}
requestLocation();
}else {
ToastUtils.showShort("發(fā)生未知錯誤");
finish();
}
break;
default:
break;
}
}
// 監(jiān)聽器
public class MyLocationListener implements BDLocationListener{
@Override
public void onReceiveLocation(BDLocation bdLocation) {
StringBuilder currentLocation = new StringBuilder();
currentLocation.append("緯度:").append(bdLocation.getLatitude()).append("\n");
currentLocation.append("經(jīng)線:").append(bdLocation.getAltitude()).append("\n");
currentLocation.append("定位方式:");
if (bdLocation.getLocType() == BDLocation.TypeGpsLocation){
currentLocation.append("GPS");
} else if (bdLocation.getLocType() == BDLocation.TypeNetWorkLocation){
currentLocation.append("網(wǎng)絡(luò)");
}
tv_show_location.setText(currentLocation);
}
}
}
運行程序切油,效果如下:
在默認情況下蝙斜,調(diào)用 LocationClient 的 start() 的方法只會定位一次,若要實時更新當前的位置澎胡,還需添加如下代碼:
public class LocationActivity extends AppCompatActivity {
. . .
/**
* 開始地理位置定位
*/
private void requestLocation() {
initLocation();
mLocationClient.start();
}
private void initLocation() {
// 創(chuàng)建LocationClientOption 對象
LocationClientOption option = new LocationClientOption();
option.setScanSpan(5000); //5秒鐘更新下當前位置
mLocationClient.setLocOption(option);
}
@Override
protected void onDestroy() {
super.onDestroy();
mLocationClient.stop();//停止定位
}
}
??這樣界面上的經(jīng)緯度信息就會跟著位置變化一起變化孕荠。
11.2.3 選擇定位模式
??上一小節(jié)是使用網(wǎng)絡(luò)定位的,那要如何使用 GPS 定位呢攻谁?
??GPS 定位功能必須由用戶主動去啟用才行稚伍,開啟后可以在 initLocation() 方法中對百度 LBS SDK 的定位模式進行指定,共有3種模式:
Hight_Accuracy
?高精度模式(默認模式)戚宦,會在GPS信號正常的情況下優(yōu)先使用GPS定位个曙,在無法接收GPS信號時用網(wǎng)絡(luò)定位。Battery_Saving
?節(jié)電模式受楼,只會使用網(wǎng)絡(luò)定位垦搬。Device_Sensors
?傳感器模式,只會使用GPS定位艳汽。
??當然悼沿,也可以調(diào)用 setLocationMode() 方法來強制指定只使用GPS定位,如下:
option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);
??重新運行程序骚灸,效果如下:
11.2.4 看得懂的位置信息
??經(jīng)緯度一般人是看不懂,為了更加直觀點慌植,還需要進行一些簡單的接口調(diào)用甚牲,如下:
public class LocationActivity extends AppCompatActivity {
. . .
private void initLocation() {
LocationClientOption option = new LocationClientOption();
option.setScanSpan(5000);
//需要獲取當前位置的詳細信息
option.setIsNeedAddress(true);
mLocationClient.setLocOption(option);
}
// 監(jiān)聽器
public class MyLocationListener implements BDLocationListener{
@Override
public void onReceiveLocation(BDLocation bdLocation) {
StringBuilder currentLocation = new StringBuilder();
currentLocation.append("緯度:").append(bdLocation.getLatitude()).append("\n");
currentLocation.append("經(jīng)線:").append(bdLocation.getAltitude()).append("\n");
currentLocation.append("國家:").append(bdLocation.getCountry()).append("\n");
currentLocation.append("省:").append(bdLocation.getProvince()).append("\n");
currentLocation.append("市:").append(bdLocation.getCity()).append("\n");
currentLocation.append("區(qū):").append(bdLocation.getDistrict()).append("\n");
currentLocation.append("街道:").append(bdLocation.getStreet()).append("\n");
currentLocation.append("定位方式:");
if (bdLocation.getLocType() == BDLocation.TypeGpsLocation){
currentLocation.append("GPS");
} else if (bdLocation.getLocType() == BDLocation.TypeNetWorkLocation){
currentLocation.append("網(wǎng)絡(luò)");
}
tv_show_location.setText(currentLocation);
}
}
}
??重新運行程序蝶柿,效果如下:
11.3 使用百度地圖
11.3.1 讓地圖顯示出來
??要讓地圖顯示出來丈钙,需要用到百度提供的自定義控件 MapView,在布局中添加如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_map"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.wonderful.myfirstcode.chapter11.MapActivity">
<!-- 顯示地圖控件 -->
<com.baidu.mapapi.map.MapView
android:id="@+id/map_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"/>
</RelativeLayout>
??接下來交汤,編寫活動中的代碼如下:
public class MapActivity extends AppCompatActivity {
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 初始化操作雏赦,在 setContentView() 方法前調(diào)用
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_map);
mapView = (MapView) findViewById(R.id.map_view);
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
}
??上述代碼劫笙,需要重寫 onResume()、onPause()星岗、onDestroy() 這3個方法填大,保證資源能夠及時釋放。
??運行效果如下:
11.3.4 移動到我的位置
??百度 LBS SDK 的 API 中提供了一個** BaiduMap** 類俏橘,是地圖的總控制器允华,有了它就能對地圖進行各種各樣的操作了。獲取其實例如下:
BaiduMap baiduMap = mapView.getMap();
??百度地圖將縮放級別的取值范圍限定在3到19之間寥掐,也可取小數(shù)點位靴寂,值越大地圖顯示信息越精細,如把縮放級別設(shè)置成12.5召耘,可以這樣寫:
MapStatusUpdate update = MapStatusUpdateFactory.zoomTo(12.5f);
baiduMap.animateMapStatus(update);
??若要讓地圖移動到某個經(jīng)緯度上百炬,可以借助 LatLng 類,如將地圖移動到北緯39.915°污它、東經(jīng)116.404°剖踊,可以這樣寫:
LatLng ll = new LatLng(39.915,116.404);
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
baiduMap.animateMapStatus(update);
??接下來實現(xiàn)下 “移動到我的位置” 這個功能,修改活動中代碼如下:
public class MapActivity extends AppCompatActivity {
private LocationClient mLocationClient;
private MapView mapView;
private BaiduMap baiduMap;
// 避免多次調(diào)用animateMapStatus() 方法
private boolean isFirstLocate = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLocationClient = new LocationClient(getApplicationContext());
mLocationClient.registerLocationListener(new MyLocationListener());
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_map);
mapView = (MapView) findViewById(R.id.map_view);
baiduMap = mapView.getMap();
. . .
}
/**
* 把地圖移動到當前位置
* @param location
*/
private void navigateTo(BDLocation location){
if (isFirstLocate){
LatLng ll = new LatLng(location.getLatitude(),location.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
baiduMap.animateMapStatus(update);
update = MapStatusUpdateFactory.zoomTo(16f);
baiduMap.animateMapStatus(update);
isFirstLocate = false;
}
}
// 監(jiān)聽器
public class MyLocationListener implements BDLocationListener{
@Override
public void onReceiveLocation(BDLocation bdLocation) {
if (bdLocation.getLocType() == BDLocation.TypeGpsLocation ||
bdLocation.getLocType() == BDLocation.TypeNetWorkLocation){
navigateTo(bdLocation);
}
}
}
. . .
}
11.3.3 讓“我”顯示在地圖上
??百度 LBS SDK 當中提供了一個 MyLocationData.Builder 類,這個類是用來封裝設(shè)備當前所在位置的盗蟆,只需將經(jīng)緯度信息傳入到它相應(yīng)的方法就可以桃漾,如下:
MyLocationData.Builder locationBuilder = new MyLocationData.Builder();
locationBuilder.latitude(39.915);
locationBuilder.longitude(116.404);
??設(shè)置完要封裝的信息后調(diào)用 MyLocationData.Builder 類中的 build() 方法,就會生成一個 MyLocationData 實例圃验,把這個實例傳入到 BaiduMap 的 setMyLocationData() 方法中,就可以讓設(shè)備當前位置顯示在地圖上了缝呕,如下:
MyLocationData locationData = locationBuilder.build();
baiduMap.setMyLocationData(locationData);
??下面貼上完整的代碼:
public class MapActivity extends AppCompatActivity {
private LocationClient mLocationClient;
private MapView mapView;
private BaiduMap baiduMap;
private boolean isFirstLocate = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLocationClient = new LocationClient(getApplicationContext());
mLocationClient.registerLocationListener(new MyLocationListener());
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_map);
mapView = (MapView) findViewById(R.id.map_view);
baiduMap = mapView.getMap();
baiduMap.setMyLocationEnabled(true);
// 聲明權(quán)限澳窑,將權(quán)限添加到list集合中再一次性申請
List<String> permissionList = new ArrayList<>();
if (ActivityCompat.checkSelfPermission(MapActivity.this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if (ActivityCompat.checkSelfPermission(MapActivity.this,
Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.READ_PHONE_STATE);
}
if (ActivityCompat.checkSelfPermission(MapActivity.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(MapActivity.this,permissions,1);
}else {
requestLocation();
}
}
/**
* 開始地理位置定位
*/
private void requestLocation() {
initLocation();
mLocationClient.start();
}
private void initLocation() {
LocationClientOption option = new LocationClientOption();
option.setScanSpan(5000); //5秒鐘更新下當前位置
option.setIsNeedAddress(true);
mLocationClient.setLocOption(option);
}
@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){
ToastUtils.showShort("必須同意所有權(quán)限才能使用本程序");
finish();
return;
}
}
requestLocation();
}else {
ToastUtils.showShort("發(fā)生未知錯誤");
finish();
}
break;
default:
break;
}
}
/**
* 把地圖移動到當前位置
* @param location
*/
private void navigateTo(BDLocation location){
if (isFirstLocate){
LatLng ll = new LatLng(location.getLatitude(),location.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
baiduMap.animateMapStatus(update);
update = MapStatusUpdateFactory.zoomTo(16f);
baiduMap.animateMapStatus(update);
isFirstLocate = false;
}
MyLocationData.Builder locationBuilder = new MyLocationData.Builder();
locationBuilder.latitude(location.getLatitude());
locationBuilder.longitude(location.getLongitude());
MyLocationData locationData = locationBuilder.build();
baiduMap.setMyLocationData(locationData);
}
// 監(jiān)聽器
public class MyLocationListener implements BDLocationListener{
@Override
public void onReceiveLocation(BDLocation bdLocation) {
if (bdLocation.getLocType() == BDLocation.TypeGpsLocation ||
bdLocation.getLocType() == BDLocation.TypeNetWorkLocation){
navigateTo(bdLocation);
}
}
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
mLocationClient.stop();
mapView.onDestroy();
baiduMap.setMyLocationEnabled(false);
}
}
??關(guān)于百度 LBS SDK 的用法入門就介紹到這,更多用法參考官方網(wǎng)站:http://lbsyun.baidu.com/ 供常。建議根據(jù)官網(wǎng)開發(fā)指南來進行學習摊聋。