先拋問題:
- locationManager.getLastKnownLocation方法返回null歇盼。
- 如何實(shí)現(xiàn)快速而又精確的定位冤馏。
手機(jī)定位方案
我們常用的定位一般也就下面這兩種發(fā)方案:
- GPS定位
- 網(wǎng)絡(luò)定位(基站定位)
最簡單的手機(jī)定位方式當(dāng)然是通過GPS模塊(現(xiàn)在大部分的智能機(jī)應(yīng)該都有了)挂签。GPS方式準(zhǔn)確度是最高的,但是它的缺點(diǎn)也非常明顯:
- 比較耗電岖寞;
- 絕大部分用戶默認(rèn)不開啟GPS模塊测暗;
- 從GPS模塊啟動到獲取第一次定位數(shù)據(jù)椒舵,可能需要比較長的時間蚂踊;
- 室內(nèi)幾乎無法使用。
這其中逮栅,缺點(diǎn)2,3都是比較致命的悴势。需要指出的是,GPS走的是衛(wèi)星通信的通道措伐,在沒有網(wǎng)絡(luò)連接的情況下也能用特纤。
另外一種常見的定位方式也就是網(wǎng)絡(luò)定位了,也就基站定位。大致思路就是采集到手機(jī)上的基站ID號(cellid)和其它的一些信息(MNC侥加,MCC捧存,LAC等等),然后通過網(wǎng)絡(luò)訪問一些定位服務(wù)担败,獲取并返回對應(yīng)的經(jīng)緯度坐標(biāo)昔穴。基站定位的精確度不如GPS提前,但好處是能夠在室內(nèi)用吗货,只要網(wǎng)絡(luò)通暢就行。
還有Wifi定位狈网。和基站定位類似宙搬,這種方式是通過獲取當(dāng)前所用的wifi的一些信息,然后訪問網(wǎng)絡(luò)上的定位服務(wù)以獲得經(jīng)緯度坐標(biāo)拓哺。因?yàn)樗突径ㄎ黄鋵?shí)都需要使用網(wǎng)絡(luò)勇垛,所以在Android也統(tǒng)稱為Network方式。另外,需要指出的是網(wǎng)上相當(dāng)一部分人說由于國內(nèi)沒有Google服務(wù),無法實(shí)現(xiàn)網(wǎng)絡(luò)定位,這個不敢茍同,用手機(jī)基站和WIFI節(jié)點(diǎn)的地址來大致定位位置士鸥,這種定位方式取決于服務(wù)器闲孤,即取決于將基站或WIF節(jié)點(diǎn)信息翻譯成位置信息的服務(wù)器的能力。市面上的手機(jī)廠商基本在手機(jī)系統(tǒng)底部是已經(jīng)接入國內(nèi)位置信息服務(wù)器的,所以說在國內(nèi)無法實(shí)現(xiàn)網(wǎng)絡(luò)定位的說法是不存在的烤礁。
不多說,來看看一般的實(shí)現(xiàn)定位的代碼:
LocationManager mLocationManager = (LocationManager) mContext.getSystemService(LOCATION_SERVICE);
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);//高精度
criteria.setAltitudeRequired(false);//無海拔要求 criteria.setBearingRequired(false);//無方位要求
criteria.setCostAllowed(true);//允許產(chǎn)生資費(fèi) criteria.setPowerRequirement(Criteria.POWER_LOW);//低功耗
// 獲取最佳服務(wù)對象
String provider = locationManager.getBestProvider(criteria,true);
locationManager.getLastKnownLocation(provider);
locationManager.getBestProvider(criteria,true);方法看起來很完美讼积,但其實(shí)返回值就network肥照、gps二選一。而且如果你要求高精度勤众,它會優(yōu)先檢查GPS建峭,如果手機(jī)開啟了GPS就返回GPS,否則返回network决摧。如果都沒開啟則返回null。
最要說的就是getLastKnownLocation()
方法,首先它獲取的是最近一次的定位信息,如果第一次運(yùn)行呢,當(dāng)然為空,即使不為空,通過它拿到的位置也未必是實(shí)時的位置信息吧凑兰。網(wǎng)絡(luò)定位耗時一般在2秒左右(網(wǎng)絡(luò)差掌桩,時間會更長), 這些都是造成getLastKnownLocation為空的原因,而且如果采取的定位方式是gps,那么90%得到的Location會為空。
那么如果實(shí)現(xiàn)盡可能的精準(zhǔn)定位呢?
谷歌是有為我們推薦的,可參看:https://developer.android.com/guide/topics/location/strategies.html
思路大概就是通過網(wǎng)絡(luò)定位和gps定位的結(jié)合,來盡可能的獲取準(zhǔn)確定位,接下來,所要討論是基于只定位一次的情況下,大部分情況下也確實(shí)是這樣!
- 開啟network和gps監(jiān)聽
- 獲得network定位信息location后,移除network監(jiān)聽
- 獲得gps定位信息location,移除gps監(jiān)聽
- 比較當(dāng)前l(fā)ocation和新獲取的location哪個更好(來自gps)
既然結(jié)合兩者姑食,就要同時為兩者添加監(jiān)聽 :
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME, MIN_DISTANCE, gpsLocationListener);
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME, MIN_DISTANCE, networkListener);
其中MIN_TIME和MIN_DISTANCE根據(jù)自己實(shí)際情況定義波岛。
網(wǎng)絡(luò)定位監(jiān)聽器:
LocationListener networkListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
if (isBetterLocation(location, mLocation)) {
mLocation = location;
}
if (mLocation != null) {
mLocationManager.removeUpdates(this);
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
};
gps定位監(jiān)聽器
LocationListener gpsLocationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
if (isBetterLocation(location, mLocation)) {
mLocationManager.removeUpdates(networkListener);
mLocation = location;
}
if (mLocation != null) {
mLocationManager.removeUpdates(this);
}
}
@Override
public void onProviderDisabled(String provider) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
isBetterLocation(Location location, Location currentBestLocation)
方法是參考的Google官方提供的,可自行查看.
最后不要忘了要清除監(jiān)聽
public void removeListener() {
if (mLocationManager != null) {
uniqueInstance = null;
mLocationManager.removeUpdates(networkListener);
mLocationManager.removeUpdates(gpsLocationListener);
}
}