Android LBS系列05 位置策略(一)


Location Strategies

 

定位的實現

  在Android系統上實現定位主要是通過GPS或者是基於網絡的定位方法。

  GPS是精度最高的,但是它只在戶外有用,並且很耗電,並且首次定位花費時間較長。

  基於網絡的定位利用通信網絡蜂窩基站和Wi-Fi信號,這種定位方式在室內室外都能用,響應時間較短,耗電較少,但是精度較差。

  為了在應用中獲得用戶的信息,你的location provider可以是GPS或者基於網絡,也可以兩者都用。

 

決定用戶位置面臨的挑戰

  從手機上獲取用戶的位置是個比較復雜的問題,無論采取的數據源是什么,總是有一些因素會導致位置信息包含誤差,從而不准確。

  誤差來源如下:

  多種位置信息源

  GPS, Cell-ID, 和Wi-Fi都能為用戶位置提供一定的線索。決定信任和采用哪些數據是一個需要權衡的過程,權衡時要考慮精度、速度、電池效率等。

  用戶移動

  因為用戶的位置會改變,所以應該考慮每隔一段時間重新估計用戶位置。

  變化的精度

  每一個位置信息源的精度不是恆定的。也就是說位置估計即便是同一個信息源提供的,它的精確度也是不斷在變化的。

 

請求位置更新

  在Android中獲取位置主要是通過回調函數。

  首先通過 LocationManager的 requestLocationUpdates()方法注冊監聽器,向其中傳入一個實現了 LocationListener接口的對象。

  你的 LocationListener對象中必須實現一些回調函數,當用戶位置改變或者當服務狀態改變時,Location Manager就會調用這些回調函數。

  比如,下面的代碼就展示了如何定義一個 LocationListener然后請求位置更新:

 

// 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);

 

   requestLocationUpdates() 中的第一個參數指明了location provider的類型,第二個參數是通知的最小時間間隔,第三個參數是通知的最小的改變距離。

  如果第二個和第三個參數都設置成0就表示要盡可能頻繁地請求位置通知。

  最后一個參數是用戶自己定義的實現了LocationListener接口的對象,它接收位置更新的回調。

  如果想要同時利用GPS和網絡定位,可以調用 requestLocationUpdates()兩次,第一個參數分別是 GPS_PROVIDER和 NETWORK_PROVIDER 

 

權限設置

  如果沒有權限設置,程序在請求位置更新時將會失敗。

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

  如果用NETWROK_PROVIDER, 那么需要聲明 ACCESS_COARSE_LOCATIONINTERNET

  如果用GPS_PROVIDER, 那么需要聲明 ACCESS_FINE_LOCATION

  ACCESS_FINE_LOCATION是包含了ACCESS_COARSE_LOCATION的,所以兩者都用時可以只聲明ACCESS_FINE_LOCATION

 

建立一個最佳性能的模型

  為了克服獲取用戶位置時的種種困難,定義一個模型,具體化你的應用如何取得用戶位置。

  這個模型包含了你何時開始和何時終止位置更新的監聽,也包含了什么時候使用緩存的位置數據。

獲取用戶位置的流程

  獲取用戶位置的典型流程如下:

                         

 

    1.首先開始應用。

    2.在某一個點,開始監聽位置更新。

    3.維持一個當前位置的“最佳估計”。

    4.停止對位置更新的監聽。

    5.利用最后一次的最佳位置估計。

  這個模型是一個窗口,窗口從開始監聽開始,從停止監聽結束。

 

決定何時開始監聽更新

  可以從應用一開始就啟動監聽,也可以在用戶觸發某個特性后開始。

  要清楚如果長時間監聽位置會消耗很多電量,但是短時間的監聽可能達不到足夠的精度。

  調用requestLocationUpdates()開始監聽:

LocationProvider locationProvider = LocationManager.NETWORK_PROVIDER;
// Or, use GPS location data:
// LocationProvider locationProvider = LocationManager.GPS_PROVIDER;

locationManager.requestLocationUpdates(locationProvider, 0, 0, locationListener);

 

用上次定位的結果獲取快速定位

  初次獲得位置信息可能會花費較長時間。在獲得一個比較精確的定位之前,可以利用一個緩存的位置:調用getLastKnownLocation(String)方法實現。

LocationProvider locationProvider = LocationManager.NETWORK_PROVIDER;
// Or use LocationManager.GPS_PROVIDER

Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);
 

決定何時停止監聽

  位置獲取和位置使用之間的時間間隔越小,對估計精度的改善越有利。

  永遠記住長時間的監聽位置更新將會非常費電,所以一旦你得到你需要的信息,就應該停止監聽位置更新,調用removeUpdates(PendingIntent)方法實現:

// Remove the listener you previously added
locationManager.removeUpdates(locationListener);
 

維護一個當前最佳估計

  因為定位精度是實時變化的,所以很可能最新的位置並不是最准確的。

  你應該制定一些標准並包含一套邏輯判斷,來選擇出最佳估計。

  這套標准也是隨着使用情景而變化的。

  下面是你驗證一個location fix的精確度時可以采取的步驟:

    1.檢查是否當期位置數據比之前的估計數據要新很多;

    2.檢查當前數據和之前數據的精度,誰更好;

    3.檢查當前數據是從哪個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);
}
 

調整模型以節約電量和進行數據交換

  當你測試模型的時候,可能發現你的模型需要做一些調整,以平衡它的准確度和性能。下面是一些你可以改變的地方:

  減小流程的窗口尺寸

  窗口尺寸減小,意味着與GPS和網絡的交互減少,這樣就可以節約電量。但是這樣也就減少了獲得最佳位置估計可以利用的位置數。

  降低location provider返回更新的頻率

  在窗口中降低更新頻率也可以改善電池效率,但是會導致精度的丟失。requestLocationUpdates() 通過其中兩個參數就可以設定更新的時間和空間間隔,從而設定頻率。

  限制provider

  根據應用的特定環境或者目標精度等級,可以選擇只利用基於網絡的定位或者只利用GPS定位,而不是同時利用兩者。只與其中的一者交互將減少電量使用,但是會有潛在的精度丟失。

 

參考資料:

  API Guides:Location Strategies

  http://developer.android.com/guide/topics/location/strategies.html

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM