知道用戶的位置信息可以使你的程序更加的智能并且能夠提供更好的信息給你的用戶,當開發一個位置感知的程序的時候,你可以使用gps或者是android的網絡位置提供者來獲取用戶的位置。雖然使用GPS最精確,但是他僅能工作在戶外,并且他更耗電量,還不能及時的返回用戶的位置信息。相比較而言,android的網絡位置提供者通過基站或者是WI-FI信號來判斷用戶的位置,它既能工作在戶外,也能工作在室內,反應迅速,耗電較少。你可以同時使用這兩種方式來獲得位置信息,也可以使用這兩種方式中的一種。
通過用戶的移動設備獲取位置信息是很復雜的,有這么幾個原因導致獲取位置時發生錯誤。
原因如下:
-
-
- 有多種方式獲取位置,可以通過GPS,Cell-ID, Wi-Fi等等,這三種方式都能讓你獲取位置信息,判斷使用哪種方式獲得的信息會牽扯到精度,響應速度和電量耗費等等問題。
- 用戶不斷的移動,那么你必須不斷的去估算用戶的位置信息
- 不斷變化的精度 從一個位置源獲取的位置信息并不是一成不變的,10秒鐘前你在A位置源獲取的位置信息可能比你從A 處或者是B處獲取的最新的位置信息要精確。
1. 請求位置更新
在定位上述的一些問題之前,讓我們先來看看如何在android上獲取位置信息。
在Android上通過回調的方式來獲取用戶位置信息,通過 LocationManager 的 requestLocationUpdates() ,方法,你就可以注冊當前的Activity給 LocationManager ,那么這個 LocationManager 就能夠周期性的通知這個已經注冊了的activity最新的位置信息,這個activity必須提供監聽器以讓 LocationManager 對調,提供的監聽器必須要實現 LocationListener 的如下幾個方法,當用戶的位置或者是網絡位置服務的狀態發生改變時,這幾個方法就會被LocationManager回調。
// 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);
引申:讓我們來看看上述代碼用到的相關的api
LocationManager: 這個類讓你能夠使用系統的位置服務,這些服務能夠讓android程序周期性的獲得設備的物理位置的更新,或者是 當用戶接近一個特別的物理位置的時候,應用程序能夠發送一個特殊的意圖提醒用戶。你不能實例化這個類獲得該類的實例對象,而是通過
Context.getSystemService(Context.LOCATION_SERVICE) 來獲取句柄
public void requestLocationUpdates ( String provider, long minTime, float minDistance, LocationListener listener)
注冊當前的activity能夠被指定的provider周期性的通知。如果當前的位置或者是指定provider的狀態發生變化的時候,當前activity提供的LocationListener會被周期性的調用。獲取最新的位置信息需要消耗一些時間,應用程序可以通過
getLastKnownLocation(String)
方法得到一個最接近的位置( 這個地方還有待斟酌 )。如果當前provider服務被用戶關閉的話,注冊更新就會停止,provider的狀態就會變為disable,
onProviderDisabled(String) 方法就會被調用。一旦當前provider又被打開,那么
onProviderEnabled 就會被調用,注冊更新又會重新開始。
通過第二個和第三個參數能夠控制位置更新的頻率。第一個參數minTime代表兩次位置更新之間的時間間隔,如果minTime大于0,那么LocationManager就會在一次更新完后,休息minTime時間,然后繼續更新,這樣能夠節省電量。第三個參數minDistance是一個位置更新的條件,因為用戶的位置可能是不斷變化的,當前后兩次位置的距離大于minDistance的時候,才會更新。如果想盡快得到獲取更新,那么把這兩個參數都設為0吧。
當保持GPS或者是無線網絡服務一直運行的時候,后臺的服務應當設置充分的時間間隔以至于設備不會消耗太多的電量,小于60000毫秒的時間間隔是不被推薦的。
調用位置服務的線程必須是含有looper的線程。
Location android.location. LocationManager .getLastKnownLocation( String provider)
從指定provider上獲取最后一個位置修正的信息,即時不開啟這個provider也能使用這個方法,但是這個時候這個provider的狀態為disable,該函數的返回值為null,注意這個返回值location有可能國企,例如關閉移動設備或者是移動到其他的位置。
問題:
1. 系統是如何緩存位置修正信息的?
getLastKnownLocation方法獲取的是最后一個緩存的位置信息,當調用requestLocationUpdates方法的時候,位置服務就會開始不斷的緩存更新的位置修正信息,當調用了removeUpdates方法停止更新的時候,緩存就會停止,這個時候調用getLastKnownLocation方法,獲取的就是最后一個緩存的位置修正信息。由于緩存的位置信息有可能過期,所以你需要判斷返回值是否為null,并作特殊處理。
2. 在手機上如何開啟位置服務呢?
以我的G3為例,打開“設置”-----》“位置“,就會看到如下界面
第一個對應NETWORK_PROVIDER
第二個對應GPS_PROVIDER
如果這里不打開服務的話,你的程序是無法獲取位置信息的。
-
2. 位置服務的權限設置
為了使用NETWORK_PROVIDER or GPS_PROVIDER來獲取位置信息,你必須要在程序中配置用戶的權限,獲取用戶的位置信息需要權限ACCESS_COARSE_LOCATION 或者ACCESS_FINE_LOCATION
<manifest ... >
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
...
</manifest>
注意:如果你使用NETWORK_PROVIDER 和GPS_PROVIDER 兩種方式的話,你只需要聲明ACCESS_FINE_LOCATION這個權限就可以了,它包括了這兩種provider所需要的權限。ACCESS_COARSE_LOCATION權限僅僅聲明了NETWORK_PROVIDER所需要的權限
3. 定義一個獲取用戶配置信息的最好的模型
一個基本的獲取獲取位置信息的程序是簡單的,但是如果要考慮到位置信息的精度,用戶的移動,獲取位置的方法,對于手機電量的需求,獲取位置是很復雜的。
你必須建立一個模型來指導你的程序如何去獲得用戶位置,這個模型演示了什么時候監聽和移除監聽位置更新,什么時候緩存位置信息數據
獲取用戶位置信息的步驟
- 開啟程序
- 開始監聽位置的更新
- 確定一個最好的當前的位置信息
- 停止監聽
- 使用最好的位置信息
4. 具體實現步驟
4.1 確定什么時間開始監聽更新
你可能在程序啟動啟動起來之后就立即開始監聽位置更新,或者是在用戶某個動作之后監聽。你需要知道的是長時間的監聽位置信息的修正很快消耗掉很多電量,但是短時間內又無法獲得充分精確地信息
LocationProvider locationProvider = LocationManager.NETWORK_PROVIDER;
// Or, use GPS location data:
// LocationProvider locationProvider = LocationManager.GPS_PROVIDER;
locationManager.requestLocationUpdates(locationProvider, 0, 0, locationListener);
4.2 使用上一個已知的位置來得到一個快速的位置修正
LocationListener獲取第一個位置修正的時間會很長,為了避免用戶等待,在你的LocationListener獲取到一個更加精確的位置之前,你應當使用 getLastKnownLocation(String) 獲取一個緩存的位置。
LocationProvider locationProvider = LocationManager.NETWORK_PROVIDER;
// Or use LocationManager.GPS_PROVIDER
Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);
4.3 確定什么時候停止監聽位置更新
確定什么時候那些新的位置修正不在需要的邏輯是簡單還是復雜取決于你的應用程序。位置信息被得到的時間和位置信息被使用的時間之間的間隔越短,位置預估的精度就越高。時刻要注意,長時間的監聽位置更新會消耗大量電量。一旦得到你所需要的信息之后,你應當立即調用 removeUpdates(PendingIntent) 方法停止監聽。
// Remove the listener you previously added locationManager.removeUpdates(locationListener);注意:這個方法必須調用,如果不調用這個方法,即時你退出了程序,仍然會被更新。
4.4 確定一個最精確的當前位置信息
你可能認為最新的位置修正時最精確的,然而因為位置修正的精度各種各樣,最新的位置修正也不一定是最好的。你應當引入一個邏輯來根據一些條件來選擇最好的位置修正。這些條件取決于你的程序
下面是一些你可以用來驗證位置修正的步驟
驗證是否獲得的位置是否明顯的比上一個要新
驗證這個位置的精度比上一個位置的精度高還是低
驗證這個位置那個provider提供的并且判斷這個provider是否可信
下面就是一個詳盡的判斷的例子:
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); }
轉自:http://www.cnblogs.com/transmuse/archive/2010/12/31/1923358.html
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

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