知道用戶的位置信息可以使你的程序更加的智能并且能夠提供更好的信息給你的用戶,當(dāng)開(kāi)發(fā)一個(gè)位置感知的程序的時(shí)候,你可以使用gps或者是android的網(wǎng)絡(luò)位置提供者來(lái)獲取用戶的位置。雖然使用GPS最精確,但是他僅能工作在戶外,并且他更耗電量,還不能及時(shí)的返回用戶的位置信息。相比較而言,android的網(wǎng)絡(luò)位置提供者通過(guò)基站或者是WI-FI信號(hào)來(lái)判斷用戶的位置,它既能工作在戶外,也能工作在室內(nèi),反應(yīng)迅速,耗電較少。你可以同時(shí)使用這兩種方式來(lái)獲得位置信息,也可以使用這兩種方式中的一種。
通過(guò)用戶的移動(dòng)設(shè)備獲取位置信息是很復(fù)雜的,有這么幾個(gè)原因?qū)е芦@取位置時(shí)發(fā)生錯(cuò)誤。
原因如下:
-
-
- 有多種方式獲取位置,可以通過(guò)GPS,Cell-ID, Wi-Fi等等,這三種方式都能讓你獲取位置信息,判斷使用哪種方式獲得的信息會(huì)牽扯到精度,響應(yīng)速度和電量耗費(fèi)等等問(wèn)題。
- 用戶不斷的移動(dòng),那么你必須不斷的去估算用戶的位置信息
- 不斷變化的精度 從一個(gè)位置源獲取的位置信息并不是一成不變的,10秒鐘前你在A位置源獲取的位置信息可能比你從A 處或者是B處獲取的最新的位置信息要精確。
1. 請(qǐng)求位置更新
在定位上述的一些問(wèn)題之前,讓我們先來(lái)看看如何在android上獲取位置信息。
在Android上通過(guò)回調(diào)的方式來(lái)獲取用戶位置信息,通過(guò) LocationManager 的 requestLocationUpdates() ,方法,你就可以注冊(cè)當(dāng)前的Activity給 LocationManager ,那么這個(gè) LocationManager 就能夠周期性的通知這個(gè)已經(jīng)注冊(cè)了的activity最新的位置信息,這個(gè)activity必須提供監(jiān)聽(tīng)器以讓 LocationManager 對(duì)調(diào),提供的監(jiān)聽(tīng)器必須要實(shí)現(xiàn) LocationListener 的如下幾個(gè)方法,當(dāng)用戶的位置或者是網(wǎng)絡(luò)位置服務(wù)的狀態(tài)發(fā)生改變時(shí),這幾個(gè)方法就會(huì)被LocationManager回調(diào)。
// Acquire a reference to the system Location Manager
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
// Called when a new location is found by the network location provider.
makeUseOfNewLocation(location);
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
// Register the listener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
引申:讓我們來(lái)看看上述代碼用到的相關(guān)的api
LocationManager: 這個(gè)類讓你能夠使用系統(tǒng)的位置服務(wù),這些服務(wù)能夠讓android程序周期性的獲得設(shè)備的物理位置的更新,或者是 當(dāng)用戶接近一個(gè)特別的物理位置的時(shí)候,應(yīng)用程序能夠發(fā)送一個(gè)特殊的意圖提醒用戶。你不能實(shí)例化這個(gè)類獲得該類的實(shí)例對(duì)象,而是通過(guò)
Context.getSystemService(Context.LOCATION_SERVICE) 來(lái)獲取句柄
public void requestLocationUpdates ( String provider, long minTime, float minDistance, LocationListener listener)
注冊(cè)當(dāng)前的activity能夠被指定的provider周期性的通知。如果當(dāng)前的位置或者是指定provider的狀態(tài)發(fā)生變化的時(shí)候,當(dāng)前activity提供的LocationListener會(huì)被周期性的調(diào)用。獲取最新的位置信息需要消耗一些時(shí)間,應(yīng)用程序可以通過(guò)
getLastKnownLocation(String)
方法得到一個(gè)最接近的位置( 這個(gè)地方還有待斟酌 )。如果當(dāng)前provider服務(wù)被用戶關(guān)閉的話,注冊(cè)更新就會(huì)停止,provider的狀態(tài)就會(huì)變?yōu)閐isable,
onProviderDisabled(String) 方法就會(huì)被調(diào)用。一旦當(dāng)前provider又被打開(kāi),那么
onProviderEnabled 就會(huì)被調(diào)用,注冊(cè)更新又會(huì)重新開(kāi)始。
通過(guò)第二個(gè)和第三個(gè)參數(shù)能夠控制位置更新的頻率。第一個(gè)參數(shù)minTime代表兩次位置更新之間的時(shí)間間隔,如果minTime大于0,那么LocationManager就會(huì)在一次更新完后,休息minTime時(shí)間,然后繼續(xù)更新,這樣能夠節(jié)省電量。第三個(gè)參數(shù)minDistance是一個(gè)位置更新的條件,因?yàn)橛脩舻奈恢每赡苁遣粩嘧兓模?dāng)前后兩次位置的距離大于minDistance的時(shí)候,才會(huì)更新。如果想盡快得到獲取更新,那么把這兩個(gè)參數(shù)都設(shè)為0吧。
當(dāng)保持GPS或者是無(wú)線網(wǎng)絡(luò)服務(wù)一直運(yùn)行的時(shí)候,后臺(tái)的服務(wù)應(yīng)當(dāng)設(shè)置充分的時(shí)間間隔以至于設(shè)備不會(huì)消耗太多的電量,小于60000毫秒的時(shí)間間隔是不被推薦的。
調(diào)用位置服務(wù)的線程必須是含有l(wèi)ooper的線程。
Location android.location. LocationManager .getLastKnownLocation( String provider)
從指定provider上獲取最后一個(gè)位置修正的信息,即時(shí)不開(kāi)啟這個(gè)provider也能使用這個(gè)方法,但是這個(gè)時(shí)候這個(gè)provider的狀態(tài)為disable,該函數(shù)的返回值為null,注意這個(gè)返回值location有可能國(guó)企,例如關(guān)閉移動(dòng)設(shè)備或者是移動(dòng)到其他的位置。
問(wèn)題:
1. 系統(tǒng)是如何緩存位置修正信息的?
getLastKnownLocation方法獲取的是最后一個(gè)緩存的位置信息,當(dāng)調(diào)用requestLocationUpdates方法的時(shí)候,位置服務(wù)就會(huì)開(kāi)始不斷的緩存更新的位置修正信息,當(dāng)調(diào)用了removeUpdates方法停止更新的時(shí)候,緩存就會(huì)停止,這個(gè)時(shí)候調(diào)用getLastKnownLocation方法,獲取的就是最后一個(gè)緩存的位置修正信息。由于緩存的位置信息有可能過(guò)期,所以你需要判斷返回值是否為null,并作特殊處理。
2. 在手機(jī)上如何開(kāi)啟位置服務(wù)呢?
以我的G3為例,打開(kāi)“設(shè)置”-----》“位置“,就會(huì)看到如下界面
第一個(gè)對(duì)應(yīng)NETWORK_PROVIDER
第二個(gè)對(duì)應(yīng)GPS_PROVIDER
如果這里不打開(kāi)服務(wù)的話,你的程序是無(wú)法獲取位置信息的。
-
2. 位置服務(wù)的權(quán)限設(shè)置
為了使用NETWORK_PROVIDER or GPS_PROVIDER來(lái)獲取位置信息,你必須要在程序中配置用戶的權(quán)限,獲取用戶的位置信息需要權(quán)限ACCESS_COARSE_LOCATION 或者ACCESS_FINE_LOCATION
<manifest ... >
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
...
</manifest>
注意:如果你使用NETWORK_PROVIDER 和GPS_PROVIDER 兩種方式的話,你只需要聲明ACCESS_FINE_LOCATION這個(gè)權(quán)限就可以了,它包括了這兩種provider所需要的權(quán)限。ACCESS_COARSE_LOCATION權(quán)限僅僅聲明了NETWORK_PROVIDER所需要的權(quán)限
3. 定義一個(gè)獲取用戶配置信息的最好的模型
一個(gè)基本的獲取獲取位置信息的程序是簡(jiǎn)單的,但是如果要考慮到位置信息的精度,用戶的移動(dòng),獲取位置的方法,對(duì)于手機(jī)電量的需求,獲取位置是很復(fù)雜的。
你必須建立一個(gè)模型來(lái)指導(dǎo)你的程序如何去獲得用戶位置,這個(gè)模型演示了什么時(shí)候監(jiān)聽(tīng)和移除監(jiān)聽(tīng)位置更新,什么時(shí)候緩存位置信息數(shù)據(jù)
獲取用戶位置信息的步驟
- 開(kāi)啟程序
- 開(kāi)始監(jiān)聽(tīng)位置的更新
- 確定一個(gè)最好的當(dāng)前的位置信息
- 停止監(jiān)聽(tīng)
- 使用最好的位置信息
4. 具體實(shí)現(xiàn)步驟
4.1 確定什么時(shí)間開(kāi)始監(jiān)聽(tīng)更新
你可能在程序啟動(dòng)啟動(dòng)起來(lái)之后就立即開(kāi)始監(jiān)聽(tīng)位置更新,或者是在用戶某個(gè)動(dòng)作之后監(jiān)聽(tīng)。你需要知道的是長(zhǎng)時(shí)間的監(jiān)聽(tīng)位置信息的修正很快消耗掉很多電量,但是短時(shí)間內(nèi)又無(wú)法獲得充分精確地信息
LocationProvider locationProvider = LocationManager.NETWORK_PROVIDER;
// Or, use GPS location data:
// LocationProvider locationProvider = LocationManager.GPS_PROVIDER;
locationManager.requestLocationUpdates(locationProvider, 0, 0, locationListener);
4.2 使用上一個(gè)已知的位置來(lái)得到一個(gè)快速的位置修正
LocationListener獲取第一個(gè)位置修正的時(shí)間會(huì)很長(zhǎng),為了避免用戶等待,在你的LocationListener獲取到一個(gè)更加精確的位置之前,你應(yīng)當(dāng)使用 getLastKnownLocation(String) 獲取一個(gè)緩存的位置。
LocationProvider locationProvider = LocationManager.NETWORK_PROVIDER;
// Or use LocationManager.GPS_PROVIDER
Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);
4.3 確定什么時(shí)候停止監(jiān)聽(tīng)位置更新
確定什么時(shí)候那些新的位置修正不在需要的邏輯是簡(jiǎn)單還是復(fù)雜取決于你的應(yīng)用程序。位置信息被得到的時(shí)間和位置信息被使用的時(shí)間之間的間隔越短,位置預(yù)估的精度就越高。時(shí)刻要注意,長(zhǎng)時(shí)間的監(jiān)聽(tīng)位置更新會(huì)消耗大量電量。一旦得到你所需要的信息之后,你應(yīng)當(dāng)立即調(diào)用 removeUpdates(PendingIntent) 方法停止監(jiān)聽(tīng)。
// Remove the listener you previously added locationManager.removeUpdates(locationListener);注意:這個(gè)方法必須調(diào)用,如果不調(diào)用這個(gè)方法,即時(shí)你退出了程序,仍然會(huì)被更新。
4.4 確定一個(gè)最精確的當(dāng)前位置信息
你可能認(rèn)為最新的位置修正時(shí)最精確的,然而因?yàn)槲恢眯拚木雀鞣N各樣,最新的位置修正也不一定是最好的。你應(yīng)當(dāng)引入一個(gè)邏輯來(lái)根據(jù)一些條件來(lái)選擇最好的位置修正。這些條件取決于你的程序
下面是一些你可以用來(lái)驗(yàn)證位置修正的步驟
驗(yàn)證是否獲得的位置是否明顯的比上一個(gè)要新
驗(yàn)證這個(gè)位置的精度比上一個(gè)位置的精度高還是低
驗(yàn)證這個(gè)位置那個(gè)provider提供的并且判斷這個(gè)provider是否可信
下面就是一個(gè)詳盡的判斷的例子:
private static final int TWO_MINUTES = 1000 * 60 * 2;
/** Determines whether one Location reading is better than the current Location fix * @param location The new Location that you want to evaluate * @param currentBestLocation The current Location fix, to which you want to compare the new one */ protected boolean isBetterLocation(Location location, Location currentBestLocation) { if (currentBestLocation == null) { // A new location is always better than no location return true; }
// Check whether the new location fix is newer or older long timeDelta = location.getTime() - currentBestLocation.getTime(); boolean isSignificantlyNewer = timeDelta > TWO_MINUTES; boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES; boolean isNewer = timeDelta > 0;
// If it's been more than two minutes since the current location, use the new location // because the user has likely moved if (isSignificantlyNewer) { return true; // If the new location is more than two minutes older, it must be worse } else if (isSignificantlyOlder) { return false; }
// Check whether the new location fix is more or less accurate int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy()); boolean isLessAccurate = accuracyDelta > 0; boolean isMoreAccurate = accuracyDelta < 0; boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// Check if the old and new location are from the same provider boolean isFromSameProvider = isSameProvider(location.getProvider(), currentBestLocation.getProvider());
// Determine location quality using a combination of timeliness and accuracy if (isMoreAccurate) { return true; } else if (isNewer && !isLessAccurate) { return true; } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) { return true; } return false; }
/** Checks whether two providers are the same */ private boolean isSameProvider(String provider1, String provider2) { if (provider1 == null) { return provider2 == null; } return provider1.equals(provider2); }
轉(zhuǎn)自:http://www.cnblogs.com/transmuse/archive/2010/12/31/1923358.html
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
