日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

android中几种定位方式详解

發(fā)布時間:2024/4/15 编程问答 101 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android中几种定位方式详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

目錄

前言:

1、GPS定位

2、NETWORK定位

3、AGPS定位

4、基站定位

5、WIFI定位

6、混合定位


目前,移動端大致通過三種方式來進(jìn)行設(shè)備定位:GPS、基站、wifi。本文就詳細(xì)的講解一下這幾種定位方式和實現(xiàn)方法。

前言:

android中我們一般使用LocationManager來獲取位置信息,這里面有四中provider:

public static final String NETWORK_PROVIDER = "network"; public static final String GPS_PROVIDER = "gps"; public static final String PASSIVE_PROVIDER = "passive"; public static final String FUSED_PROVIDER = "fused";

區(qū)別如下:

(1)GPS_PROVIDER:通過 GPS 來獲取地理位置的經(jīng)緯度信息; 優(yōu)點:獲取地理位置信息精確度高; 缺點:只能在戶外使用,獲取經(jīng)緯度信息耗時,耗電;

(2)NETWORK_PROVIDER:通過移動網(wǎng)絡(luò)的基站或者 Wi-Fi 來獲取地理位置; 優(yōu)點:只要有網(wǎng)絡(luò),就可以快速定位,室內(nèi)室外都可; 缺點:精確度不高;

(3)PASSIVE_PROVIDER:被動接收更新地理位置信息,而不用自己請求地理位置信息。

PASSIVE_PROVIDER 返回的位置是通過其他 providers 產(chǎn)生的,可以查詢 getProvider() 方法決定位置更新的由來,需要 ACCESS_FINE_LOCATION 權(quán)限,但是如果未啟用 GPS,則此 provider 可能只返回粗略位置匹配;

(4)FUSED_PROVIDER:這個本來已經(jīng)被廢棄了,但是目前在Android12(即android api 31)上又重新使用了起來,但是它依賴GMS,所以國內(nèi)暫時無法使用。

我們通常使用gps和network這兩種方式。

但是我們還可以通過其它方式獲取位置信息,這篇文章就詳細(xì)的講解一下在android中幾種獲取定位的方式。

1、GPS定位

這個用的最普遍,可以獲取上次定位,也可以監(jiān)聽變化,代碼如下:?

需要權(quán)限

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

GPS定位

var locManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager var loc = locManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) if(loc != null){Log.e("gpslocation", loc.toString())toast(loc.toString()) } locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0F, object : LocationListener{override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {}override fun onProviderEnabled(provider: String?) {}override fun onProviderDisabled(provider: String?) {}override fun onLocationChanged(location: Location?) {Log.e("gpslocation", location.toString())toast(location.toString())} })

2、NETWORK定位

與gps定位代碼基本一致,只不過將provider改成LocationManager.NETWORK_PROVIDER

3、AGPS定位

實際上是將上面兩種定位結(jié)合起來,具體原理如下:

AGPS手機(jī)首先將本身的基站地址通過網(wǎng)絡(luò)傳輸?shù)轿恢梅?wù)器;

位置服務(wù)器根據(jù)該手機(jī)的大概位置傳輸與該位置相關(guān)的GPS輔助信息(包含GPS的星歷和方位俯仰角等)到手機(jī);

該手機(jī)的AGPS模塊根據(jù)輔助信息(以提升GPS信號的第一鎖定時間TTFF能力)接收GPS原始信號;

手機(jī)在接收到GPS原始信號后解調(diào)信號,計算手機(jī)到衛(wèi)星的偽距(偽距為受各種GPS誤差影響的距離),并將有關(guān)信息通過網(wǎng)絡(luò)傳輸?shù)轿恢梅?wù)器;

位置服務(wù)器根據(jù)傳來的GPS偽距信息和來自其他定位設(shè)備(如差分GPS基準(zhǔn)站等)的輔助信息完成對GPS信息的處理,并估算該手機(jī)的位置;

位置服務(wù)器將該手機(jī)的位置通過網(wǎng)絡(luò)傳輸?shù)蕉ㄎ痪W(wǎng)關(guān)或應(yīng)用平臺。

我的理解就是通過網(wǎng)絡(luò)位置和位置服務(wù)器判斷出最佳的衛(wèi)星,減少了獲取衛(wèi)星信號的時間。因為網(wǎng)絡(luò)位置獲取很快,所以可以減少整體的定位時間。

AGPS并不是一種定位方式,只是一種優(yōu)化方案,代碼與GPS一樣,只不過在設(shè)置中將定位模式設(shè)成AGPS。


上面是android自帶的定位方式,我們還可以獲取一些原始信息(比如基站信息、wifi信息),通過公開的接口來獲取位置信息。下面幾種方式就是使用原始信息通過API來獲取位置信息。


4、基站定位

通過TelephonyManager我們可以拿到基站信息,再通過相關(guān)的api接口就能得到經(jīng)緯度,但是基站定位精度很差。


基站信息包含如下:

MCC,Mobile Country Code,移動國家代碼(中國的為460);
MNC,Mobile Network Code,移動網(wǎng)絡(luò)號碼(中國移動為00,中國聯(lián)通為01);
LAC,Location Area Code,位置區(qū)域碼;
CID,Cell Identity,基站編號,是個16位的數(shù)據(jù)(范圍是0到65535)。


拿到這個信息后,我們可以通過一些公開的api服務(wù)拿到經(jīng)緯度,如下:

http://www.google.com/loc/json? ?google的,post請求,好像停用了

接口說明文檔 | LBS數(shù)據(jù)倉庫? 目前可用,是免費的

實例:

http://api.cellocation.com:82/cell/?mcc=460&mnc=1&lac=4301&ci=20986&output=json

返回:

{"errcode":0, "lat":"40.00598145", "lon":"116.48539734", "radius":"937", "address":"北京市朝陽區(qū)來廣營地區(qū)東湖渠;溪陽東路與屏翠東路路口東70米"}


接口參數(shù):

名稱類型必填說明
mccintmcc國家代碼:中國代碼 460
mncintmnc網(wǎng)絡(luò)類型:0移動,1聯(lián)通(電信對應(yīng)sid),十進(jìn)制
lacintlac(電信對應(yīng)nid),十進(jìn)制
ciintcellid(電信對應(yīng)bid),十進(jìn)制
coordstring坐標(biāo)類型(wgs84/gcj02/bd09),默認(rèn)wgs84
outputstring返回格式(csv/json/xml),默認(rèn)csv

另外還有很多提供這種接口和數(shù)據(jù)的平臺,自己搜索即可

代碼如下:

需要權(quán)限

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

?基站定位,這里只實現(xiàn)了GSM的,CDMA的有些許不同

val telManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager if(telManager.cellLocation is GsmCellLocation) {val cellLoc = telManager.cellLocation as GsmCellLocationif (cellLoc != null) {val operator = telManager.networkOperatorval mcc = operator.substring(0, 3).toInt()val mnc = operator.substring(3).toInt()val cid = cellLoc.cidval lac = cellLoc.lac...doAsync {val result = URL(sb.toString()).readText()Log.e("tellocation", result)}} }

5、WIFI定位

wifi定位是通過WifiManager拿到wifi的信息,主要是wifi的BSSID(即mac地址)。然后通過一些api查詢經(jīng)緯度,比如接口說明文檔 | LBS數(shù)據(jù)倉庫

實例:

http://api.cellocation.com:82/wifi/?mac=00:87:36:05:5d:ea&output=json

返回:

{"errcode":0, "lat":"39.950008", "lon":"116.230049", "radius":"222", "address":"北京市海淀區(qū)四季青鎮(zhèn)益園文創(chuàng)基地c區(qū)9號樓;南平莊中路與西平莊路路口西北561米"}

接口參數(shù):

名稱類型必填說明
macstringWIFI熱點的MAC地址(BSSID)
coordstring坐標(biāo)類型(wgs84/gcj02/bd09),默認(rèn)wgs84
outputstring返回格式(csv/json/xml),默認(rèn)csv

代碼如下:

需要權(quán)限

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

?wifi定位

val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager if(wifiManager.isWifiEnabled) {var mac = wifiManager.connectionInfo.bssidif(TextUtils.isEmpty(mac)) {/*** 當(dāng)未鏈接wifi時,可以使用掃描到的wifi列表中找一個信號強度最好的。這里沒進(jìn)行比較,直接使用第一個了* ScanReuslt有三個字段比較重要:SSID是wifi名稱,BSSID是wifi的mac,level則是信號強度(負(fù)數(shù))* 注意結(jié)果中同一個SSID可能會有多個,如果需要鏈接wifi可以通過信號強度過濾出最好的來鏈接*/val scanlist = wifiManager.scanResultsfor(info in scanlist){Log.e("wifiinfo", info.toString())}if(scanlist.size > 0) {mac = wifiManager.scanResults[0].BSSID}}if(!TextUtils.isEmpty(mac)) {...doAsync {val result = URL(sb.toString()).readText()Log.e("wifilocation", result)}} }

6、混合定位

混合定位就是獲取附近的wifi列表信息(包括信號強度)和附近的基站列表信息(包括信號強度),通過一些api獲取經(jīng)緯度。

這種方式相對于單一的基站和wifi定位要更精確一些。

獲取附近的wifi列表在WIFI定位已經(jīng)提到過了,通過WifiManager的getScanResults函數(shù)獲取掃描到的wifi列表,其中l(wèi)evel就是信號強度,可能需要做一下去重。

獲取附近的基站列表則有些問題。

官方提供了一個方式,通過TelephonyManager的getNeighboringCellInfo函數(shù)獲得,其中mRssi就是信號強度。

需要權(quán)限

<uses-permission?android:name="android.permission.ACCESS_COARSE_LOCATION"/>

獲取附近基站信息

val telManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager val neighborCells = telManager.neighboringCellInfo for(cell in neighborCells){//這里將rssi轉(zhuǎn)化為dBmval level = -131 + 2 * cell.rssiLog.e("neighboringCellInfo", "cid:${cell.cid} lac:${cell.lac} rssi:$level") }

但是實際使用時發(fā)現(xiàn)cid和lac都是-1。

檢查NeighboringCellInfo的構(gòu)造方法,如下:

public NeighboringCellInfo(int rssi, String location, int radioType) {// set default valuemRssi = rssi;mNetworkType = NETWORK_TYPE_UNKNOWN;mPsc = UNKNOWN_CID;mLac = UNKNOWN_CID;mCid = UNKNOWN_CID;// pad location string with leading "0"int l = location.length();if (l > 8) return;if (l < 8) {for (int i = 0; i < (8-l); i++) {location = "0" + location;}}// TODO - handle LTE and eHRPD (or find they can't be supported)try {// set LAC/CID or PSC based on radioTypeswitch (radioType) {case NETWORK_TYPE_GPRS:case NETWORK_TYPE_EDGE:mNetworkType = radioType;// check if 0xFFFFFFFF for UNKNOWN_CIDif (!location.equalsIgnoreCase("FFFFFFFF")) {mCid = Integer.parseInt(location.substring(4), 16);mLac = Integer.parseInt(location.substring(0, 4), 16);}break;case NETWORK_TYPE_UMTS:case NETWORK_TYPE_HSDPA:case NETWORK_TYPE_HSUPA:case NETWORK_TYPE_HSPA:mNetworkType = radioType;mPsc = Integer.parseInt(location, 16);break;}} catch (NumberFormatException e) {// parsing location errormPsc = UNKNOWN_CID;mLac = UNKNOWN_CID;mCid = UNKNOWN_CID;mNetworkType = NETWORK_TYPE_UNKNOWN;}}

可以看到只對GPRS和EDGE網(wǎng)絡(luò)進(jìn)行了處理,而3G、4G網(wǎng)絡(luò)都是UNKNOWN_CID,即-1。說明這種方法不支持,已經(jīng)過時。

官方還有另外一個方式,通過TelephonyManager的getAllCellInfo函數(shù)獲得。這個函數(shù)要求minsdkverison必須在17及以上

需要權(quán)限

<uses-permission?android:name="android.permission.ACCESS_COARSE_LOCATION"/>

獲取基站信息,這里只處理了LTE網(wǎng)絡(luò)的

val telManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager val cells = telManager.allCellInfo for(cell in cells){if(cell is CellInfoLte) {Log.e("celllist", "cid:${cell.cellIdentity.ci} lac:${cell.cellIdentity.tac} dbm:${cell.cellSignalStrength.dbm} isRegistered:${cell.isRegistered}")} }

得到的信息如下:

E/celllist: cid:3912981 lac:4154 dbm:-87 isRegistered:true

E/celllist: cid:2147483647 lac:2147483647 dbm:-101 isRegistered:false

E/celllist: cid:2147483647 lac:2147483647 dbm:-102 isRegistered:false

E/celllist: cid:2147483647 lac:2147483647 dbm:-108 isRegistered:false

E/celllist: cid:2147483647 lac:2147483647 dbm:-101 isRegistered:false

其中第一個是我們正在使用的基站,可以看到正常的返回了信息,而其余的則返回默認(rèn)的信息(Integer.MAX_VALUE)

說明這個方法也只能拿到當(dāng)前使用的基站信息。而且據(jù)網(wǎng)上的說法,當(dāng)使用2G網(wǎng)絡(luò),getAllCellInfo得到的是NULL。

這樣目前沒有更好的方式獲取多個基站信息了。

當(dāng)我們拿到附近的基站信息和wifi信息,可以通過http://www.cellocation.com/interfac/ 提供的混合定位接口查詢位置信息,與上面類似,這里不細(xì)說了。

總結(jié)

一般情況下,我們使用系統(tǒng)提供的LocationManager即可獲取位置信息,方便簡單。如果我們有自己的基站或wifi信息庫,也可以獲取相關(guān)源信息通過接口來實現(xiàn)個性化服務(wù)。

源碼

關(guān)注公眾號:BennuCTech,發(fā)送“多定位”獲取源碼

?

總結(jié)

以上是生活随笔為你收集整理的android中几种定位方式详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。