Android Studio開發(五)使用百度地圖API實現實時定位
Android Studio開發(五)使用百度地圖API實現實時定位
一、任務需求
- 閱讀百度地圖開發者文檔,進行基於百度地圖的簡單應用開發。
- 需要實現的基本功能:實時定位,在地圖上標記出使用者所在的位置。
二、安卓基於位置的服務(Location Based Service, LBS)
1. LBS定義
位置服務(Location Based Services,LBS)又稱定位服務,是指通過GPS衛星或者網絡(WiFi或GPRS)
獲取各種終端的地理座標(經度和緯度),在電子地圖平臺的支撐下,爲用戶提供基於位置導航、查詢的一種信息服務。
目前,使用LBS服務的應用涉及到了我們生活的方方面面,諸如美團、餓了麼、各類地圖app,各類運動app以及最近的戰疫健康打卡等,學會使用LBS還是有很大幫助的。
2. 三種常見的定位模式
目前,常見的三種定位模式爲:
- GPS定位
- Wi-Fi定位
- 基站定位
接下來,我來做一個關於這三種定位模式的簡單梳理。
2.1 GPS定位
全球定位系統(Global Positioning System,GPS)是一種以人造地球衛星爲基礎的高精度無線電導航的定位系統,它在全球任何地方以及近地空間
都能夠提供準確的地理位置、車行速度及精確的時間信息。概括地說,利用手機gps硬件定位,實現簡單,手機本地就能實現定位,不需要和服務端進行交互。
//僞代碼
LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5, listener);
然而,使用GPS定位具有一定的侷限性。當使用者處在橋樑下、大樹下、建築物內、隧道內時,手機很多時候都無法接收到GPS信號,這時GPS定位服務將無法使用,或者說信號極度微弱。
在室內無法定位是gps定位的最大問題,此時就得利用WiFi定位了。
2.2 Wi-Fi定位
看名字可能很多人覺得奇怪,Wi-Fi怎麼能知道我的位置呢,難道Wi-Fi硬件會返回位置嗎?其實這些Wi-Fi都不能做到。
Wi-Fi定位的原理是,我們在室外的時候,手機能接收到gps位置信息,也能掃描到WiFi,當手機把gps位置和WiFi傳到後端服務器,WiFi和gps位置就建立了映射關係,當手機在室內無法接收到gps時,卻能掃描WiFi,手機把WiFi傳到服務器查詢出對應的gps位置,然後進行計算可以得到位置結果(經緯度),其中映射和計算是很複雜的過程,感興趣的同學可以查閱相關資料。wifi定位需要wifi開啓,並且手機能上網。
2.3 基站定位
當手機無法掃描到WiFi時,只要裝了sim卡,就能連接移動或聯通等基站,即可用基站定位,定位原理和WiFi大致相同。基站定位需要裝了sim卡,並且手機能上網。
wifi定位與基站定位統稱爲網絡定位,當wifi關閉,或者掃描不到WiFi列表時,sdk只會把獲取的基站信息發給服務端,進行基站定位;如果沒有sim,wifi開啓,則sdk會把掃描到的WiFi信息發給服務端,進行wifi定位;如果既有wifi又有基站,則sdk會把這兩者信息都發給服務端,具體用哪一種定位,不太確定,但絕大多數情況下都是用wifi定位的。
在室內無gps時,百度定位就是利用的WiFi和基站定位的,在室外有gps時,百度是利用的android自帶的LocationManager進行定位,當然室外也可以用WiFi基站定位。
2.4 三種定位方式總結
定位方式 | 總結 |
---|---|
gps定位 | 精度很高,幾米到十幾米,但是耗電嚴重 |
WiFi定位 | 精度相對於gps差一點,但是也能到十幾米、幾十米,也有上百米的誤差的,低耗電 |
基站定位 | 精度很差,一般都有幾百米,上千米的誤差 |
這個誤差其實和wifi、基站的信號覆蓋半徑有關,wifi覆蓋半徑大概100m左右,而基站的覆蓋半徑就到km級別了。
三、使用百度地圖API進行簡單定位
1. 獲取SDK
- 申請開發者賬戶
- 創建應用,這裏簡單地給大家個教程:
官方給出的獲取SHA1的方法稍微不小心容易出錯(項目包名稱的方法可以參考),這裏給出一個更簡易的方法,在需要使用SDK的項目中,打開Gradle,app-->Tasks-->android-->signingReport
,雙擊後即可在控制檯看到SHA1代碼了。
信息填寫完確認提交後,即可得到對應的AK(API Key),即我們需要的SDK。
(注意,AK和項目一一對應,不能一對多使用)
2. 配置百度地圖API
- 下載所需對應功能的jar包資源
- 將下載的壓縮包文件解壓至app目錄下的lib文件夾中
- 在
app目錄下的build.gradle文件
中android塊中配置sourceSets
標籤,如果沒有使用該標籤則新增,詳細配置代碼如下:
sourceSets {
main {
jniLibs.srcDir 'libs'
}
}
記得重新編譯gradle,不然下面一步的service會找不到com.baidu.location.f,然後飄紅
5. 在AndroidManifest.xml
文件中進行相關配置:
- 在application標籤下添加如下代碼
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="你申請到的AK"/>
<service android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote"/>
- 聲明權限
<!-- 這個權限用於進行網絡定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
<!-- 這個權限用於訪問GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
<!-- 用於訪問wifi網絡信息,wifi信息會用於進行網絡定位-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<!-- 獲取運營商信息,用於支持提供運營商信息相關的接口-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<!-- 這個權限用於獲取wifi的獲取權限,wifi信息會用來進行網絡定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
<!-- 用於讀取手機當前的狀態-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
<!-- 寫入擴展存儲,向擴展卡寫入數據,用於寫入離線定位數據-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<!-- 訪問網絡,網絡定位需要上網-->
<uses-permission android:name="android.permission.INTERNET" />
<!-- SD卡讀取權限,用戶寫入離線定位數據-->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"></uses-permission>
3. 編碼階段
這裏其實百度地圖的Android定位開發文檔有着較好的說明示例,主要參照開發文檔即可實現簡單的定位功能了。
這裏展示部分代碼如下:
private void requestLocation() {
MyLocationListener myLocationListener = new MyLocationListener();
mLocationClient = new LocationClient(getApplicationContext());
mLocationClient.registerLocationListener(myLocationListener);
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_main);
mapView = findViewById(R.id.bmapView);
baiduMap = mapView.getMap();
baiduMap.setMyLocationEnabled(true);
txtPosition = findViewById(R.id.txtPosition);
LocationClientOption option = new LocationClientOption();
option.setScanSpan(1000);//每一秒發送一次
option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
option.setIsNeedAddress(true);
mLocationClient.setLocOption(option);
mLocationClient.start();//啓動位置請求
}
private class MyLocationListener extends BDAbstractLocationListener {
@Override
public void onReceiveLocation(BDLocation bdLocation) {
StringBuffer currentPosition = new StringBuffer();
currentPosition.append("Longitude: ").append(bdLocation.getLongitude()).append("\n");
currentPosition.append("Latitude: ").append(bdLocation.getLatitude());
String s = "" + bdLocation.getLatitude();
txtPosition.setText(currentPosition);
if (bdLocation.getLocType() == BDLocation.TypeGpsLocation || bdLocation.getLocType() == BDLocation.TypeNetWorkLocation) {
setMyLocation(bdLocation);
}
}
}
private void setMyLocation(BDLocation bdLocation) {
if (isFirstLocation) {
LatLng latLng = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(latLng);
MyLocationData locationData = new MyLocationData.Builder().latitude(latLng.latitude).longitude(latLng.longitude).build();
baiduMap.animateMapStatus(update);
baiduMap.setMyLocationData(locationData); // 地圖上顯示定位點
isFirstLocation = false;
}
}
四、實現效果
這裏需要說明,由於我本人沒有安卓設備,在模擬器上運行無法獲取實際地理座標(之後借來了別人的安卓設備進行調試,定位成功)。感興趣且有條件的讀者可以下載下來這個小項目進行真機測試,本次項目對應源碼附在文末。
本次項目對應源碼
p.s.: 最近臨近期末太忙了,上次的AS開發(四)一定會找機會把內容完善的!