1. 程式人生 > >Android學習筆記(五六:位置Location

Android學習筆記(五六:位置Location

建議更新20130522的ADT版本,無論是Linux下還是Windows下,我覺得速度快了很多。而且將Android SDK Tool升級到ver 22版本後,原來的ADT有很多不明原因問題,載入App到模擬器上出現連線不上的情況。

允許應用具備定位功能

Location是手機功能的一大特色,衛星導航除了GPS外,還有歐洲的伽利略和我國的北斗,此外還有運營商移動基站的三角定位、第三方提供WiFi熱點定位等方式。相關推薦可以閱讀CDMA的定位方式。利用基站訊號的強弱進行三角特定的方式(在市區內受到建築阻擋和反射等影響),利用上網的AP所出的地理位置來進行定位,都屬於粗定位coarse location,利用衛星的精確定位為fine location。應用要具備定位功能,首先必須進行許可權許可。

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

在模擬器中設定位置

我們可以通過DDMS在模擬器中設定經緯度,並在程式執行是修改經緯度。Window -> Open perspective -> DDMS

連續位置獲取小例子

下面的例子很簡單,UI是一個TextView用來顯示資訊。我們進行裝置位置的不斷跟蹤,也就是跟蹤我們的路徑。

public class LocationBase extends Activity{    private TextView myText;     private String textStr = "";     private LocationManager mgr=null;                protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);         setContentView(R.layout.pure_text_view);         myText = (TextView) findViewById(R.id.pure_text);         addText("Location Based-Services Demo...");

               //步驟 1: 獲取系統的定位管理器         mgr = (LocationManager)getSystemService(LOCATION_SERVICE);        addText("get system Location Manager " + mgr);}                  //步驟2.2 持續跟蹤中的停止update:在本例中,我們要求不斷獲得位置更新,我們必須在人工進行removeUpdates(),否則即使應用中所有的Activity都關閉,App仍繼續在不斷更新位置資訊,導致應用資源無法被回收    protected void onPause() {          super.onPause();         mgr.removeUpdates(onLocationChange);         addText("Remove Updates...");     }      //步驟2:設定持續跟蹤    //步驟 2.1(1) :我們在onResume()中持續跟蹤,相應的在onPause()中關閉出現跟蹤。我們只在Activity執行時進行跟蹤。具體見Activity的生命週期    protected void onResume() {         super.onResume();          //步驟2.1 (2):由於人的位置是不斷變化,我要設定一個位置變化的範圍,包括同時滿足最小的時間間隔和最小的位移變化,如果兩個條件要同時滿足,將位置監聽器將被觸發。實際上該方法有多個引數格式,特別是requestLocationUpdates (long minTime, float minDistance, Criteria criteria,PendingIntent intent),當位置變化時可呼叫其他的Activity。 在本例中,我們制定用GPS,則在許可權中必須要求精確定位許可。        mgr.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000/*10秒,為測試方便*/, 1000/*1公里*/, onLocationChange/*位置監聽器*/);        addText("Request Updates automatically ...");    }     //步驟3:位置監聽器LocationListener 的設定,當位置發生變化是觸發onLocationChanged( )    LocationListener onLocationChange = new LocationListener(){         public void onLocationChanged(Location location) {              addText("Location Changed : (" + location.getLongitude()+","+location.getLatitude()+")");        }          public void onProviderDisabled(String arg0) {              addText("onProviderDisabled");         }          public void onProviderEnabled(String arg0) {              addText("onProviderEnabled");         }          public void onStatusChanged(String arg0, int arg1, Bundle arg2) {             addText("onStatusChanged");         }              };     private void addText(String s){         textStr = textStr.concat(s + "\n\n");         myText.setText(textStr);     } }

我們可能會發現一開始並沒有出發到位置監控器的onLocationChanged(),在實際中,可能由於GPS沒有開啟,或者剛開啟,不能馬上得到位置資訊。在模擬器中,我們在DDMS中將按“send”按鈕即可。更改位置資訊,同樣需按“send”。

關於定位的選定

在例子中,我們指定了採用GPS,實際上位置獲取可以通過衛星,運營商,以及第三方服務獲取,即有多個資訊來源。我們可以想系統查詢可用的位置資訊源,如下:

List<String> list = mgr.getAllProviders(); //mgr即LocationManagerfor(Iterator<String> i = list.iterator();i.hasNext();){   System.out.println("\t" + i.next());  }

我們可以重中進行選擇,或者讓使用者選擇,但是更好的方式是讓系統幫忙選擇。如下:

Criteria criteria = new Criteria(); String providerName = mgr.getBestProvider(criteria, true /*enabledOnly*/); //criteria不能填null,否則出現異常 LocationProvider provider = mgr.getProvider(providerName);

我們可以在criteria中加入一些條件,例如一些精度setAccuracy(),和一些位置資訊setAltitudeRequired( ),是否收費setCostAllowed( )等。不是隨有的條件都必須滿足,將為你匹配最好的一個,當然如果你設定了免費,不會選擇收費給你的。我們根據provider的名字獲得LocationProvider的物件,但一般不需要,我們知道provider的名字,就可以向系統請求位置資訊。

Location location = mgr.getLastKnownLocation(providerName); if(location != null)     System.out.println("Get Location from " + providerName + " : " + location.getLatitude()+ "," + location.getLongitude());

Android採用getLastKnownLocation( )來查詢,而不是當前的實時資訊。有可能由於某種情況無法獲取,例如GPS沒有開啟,或正在啟動過程中,有可能返回null。返回的資訊可能不僅有經緯度,是否有具有海拔資訊,用location.hasAltitude()詢問,是否具有速度資訊,用hasSpeed()詢問。

到達某個位置的提醒觸發

當用戶位置到達某個目標附近 ,觸發提醒,這可以用在很多使用場景,LocationManager中可以通過addProximityAlert(),當在某位置附近可以調起pendingIntent。

public void addProximityAlert (double latitude /*維度*/,                                               double longitude/*精度*/,                                               float radius/*半徑範圍*/,                                               long expiration/*失效,-1表示沒有失效,可以用removeProximityAlert()來進行人工刪除*/,                                               PendingIntent intent /*觸發處理*/)

對比兩個location資料

對於前後獲取的location(可能來自不同的provider,也可能獲取位置資訊的條件發生變化,例如尋找多一顆衛星或少了一顆衛星,導致前後的精度有明顯差異),我們可以判斷哪個location更好地代表當前的地點。我們可以用location.getTime()來獲得定位資訊的更新時間,用location.getAccruacy()來獲取精度,用location.getProvider()反過來獲取providerName,用於進行提供者的比對。通過這些比較我們可以選取我們仍未最好的資料。在Android的開發者網站中給出 了選擇哪個location的例子。