標籤:
Android定位服務融合了GPS定位、移動通訊、導航等多種技術,提供與空間位置相關的綜合應用服務。近些年來,基於位置的服務發展更為迅速,涉及商務、醫學、工作和生活的各個方面,為使用者提供定位、追蹤和敏感地區警告等一系列服務。
Android平台支援提供位置服務的API,在開發過程中主要使用LocationManager和LocationProviders對象。
- LocationManager:
用來擷取當前位置,追蹤裝置的移動路線,或設定敏感地區,在進入或離開敏感地區時裝置會發出特定警報。
- LocationProviders:
提供定位功能的組件集合,集合中的每種組件以不同的技術提供裝置的當前位置,區別在於定位的精度、速度和成本等方面。
為了使開發的程式能夠提供位置服務,首先的問題是如何擷取LocationManager。擷取LocationManager可以通過調用android.app.Activity.getSystemService()函數擷取,代碼如下:
String serviceString = Context.LOCATION_SERVICE;LocationManager locationManager = (LocationManager) getSystemService(serviceString);
其中Context.LOCATION_SERVICE指明擷取的是位置服務,Android(API 23)支援的系統級服務如下表:
| Context類的靜態常量 |
值 |
返回對象 |
說明 |
| LOCATION_SERVICE |
location |
LocationManager |
控制位置等裝置的更新 |
| WINDOW_SERVICE |
window |
WindowManager |
最頂層的視窗管理器 |
| LAYOUT_INFLATER_SERVICE |
layout_inflater |
LayoutInflater LocationManager |
將XML資源執行個體化為View |
| POWER_SERVICE |
power |
PowerManager |
電源管理 |
……
在這裡我只列舉了以上四個,其他的可在Android SDK中關於public Object getSystemService (String name) 方法下查看,目前共有19個系統級服務,我們也沒必要全部牢記,在使用相應系統服務的時候可查看SDK文檔。這些系統服務的使用方法也相似,只不過返回的管理物件類型不同,其返回的管理對象的類型隨被請求的名稱而變化。比如Context.LOCATION_SERVICE 對應返回的是LocationManager類型對象,Context.WIFI_SERVICE對應返回的是WifiManager類型對象。
回到我們此文的重點:LBS(Location-Based Services),在擷取LocationManager之後,還需要指定LocationManager的定位方法,然後才能夠調用LocationManager.getLastKnowLocation()方法擷取當前位置。
那麼LocationManager的定位方法都有哪些呢?在某2012年出版的高等院校Android教材中寫到:
目前LocationManager中主要有兩種定位方法,分別是GPS定位和使用網路定位。
現在都2016年了,我不知道2012年有到底有幾種定位方法,但我現在不能沒有責任的告訴大家四年前的知識。於是查閱資料,得到在LocationManager中關於GPS定位、網路定位對應的靜態常量分別為GPS_PROVIDER、NETWORK_PROVIDER。而provider是供應的意思,為了更易理解,我也建議大家把“定位方法”這種理解方式拋棄,更換為“位置提供者”。在LocationManager中除了上面的兩種“位置提供者”,還有另外另外兩種“位置提供者”,分別是PASSIVE_PROVIDER 和 FUSED_PROVIDER。
LocationManager的位置提供者有以下四種:
- GPS定位(GPS_PROVIDER)
利用衛星提供精確的位置資訊,需要android.permissions.ACCESS_FINE_LOCATION使用者權限
- 網路定位(NETWORK_PROVIDER)
利用基站或Wi-Fi訪問提供近似的位置資訊,這種定位方式取決於伺服器,即取決於將基站或WIF節點資訊翻譯成位置資訊的伺服器的能力。需要許可權:android.permission.ACCESS_COARSE_LOCATION或android.permission.ACCESS_FINE_LOCATION
- 被動定位(PASSIVE_PROVIDER)
一個懶惰的位置提供者,它用於接收位置,而並沒有像GPS定位、網路定位那樣去自己擷取位置資訊。借用文檔中的一句英語描述它: This provider will return locations generated by other providers.
- 融合定位(FUSED_PROVIDER)
該提供者結合了所有可能的位置源的輸入,提供最佳的位置固定。引用一段英文描述:
Fused Location provider makes things very easy for the developers.The Fused Location Provider intelligently manages the underlying location technology and gives you the best location according to your needs. It’s simple to use, provide immediate location, power efficient and part of Google Play Service.
簡單介紹了這四種位置提供者,我們就來選擇一種來擷取位置資訊吧!代碼也非常簡單:
String provider = LocationManager.GPS_PROVIDER; Location location = locationManager.getLastKnownLocation(provider);
上面擷取到的Location對象中,包含了可以確定位置的資訊,如經度、維度和速度等。執行個體代碼如下:
double latitude = location.getLatitude();//維度double longitude = location.getLongitude();//經度
然而在提供定位服務的應用程式中,不僅需要擷取當前的位置資訊,還需要監視位置的變化,這和監聽一個按鈕的點擊事件一個道理。LocationManager提供了一種便捷、高效的位置監視方法 requestLocationUpdate(),可以根據位置的距離變化和時間間隔設定,產生位置改變時間的條件,這樣可以避免因微小的距離變化而產生大量的位置改變事件。LocationManager中設定監聽位置變化的代碼如下:
locationManager.requestLocationUpdates(provider, 2000, 0, locationListener);
第一個參數是位置提供者;第二個參數是產生位置改變時間的時間間隔(微秒);第三個參數是距離條件(米);第四個參數是回呼函數,用來處理位置改變時間。實現locationListener的代碼如下:
private final LocationListener locationListener = new LocationListener() { @Override public void onLocationChanged(Location location) { } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } };
- onLocationChanged() 在位置改變時被調用
- onStatusChanged() 在定位功能硬體狀態改變時被調用
- onProviderEnabled 在使用者啟用具有定位功能的硬體時被調用
- onProviderDisabled() 在使用者禁用具有定位功能的硬體時被調用
最後,在AndroidManifest.xml檔案中加入響應的許可權允許,大功告成,我們就可以使用GPS定位功能了!
如果你對過程還是有點模糊,來看下面這個簡單Demo:
介面效果
通過DDMS將虛擬位置資訊發送到Android模擬器中:
(親測Genymotion、AS原生AVD(API22) 不可用DDMS…原因不詳)
MainActivity.java的完整代碼如下:
package com.example.currentlocationdemo;import android.Manifest;import android.content.Context;import android.content.pm.PackageManager;import android.location.Location;import android.location.LocationListener;import android.location.LocationManager;import android.support.v4.app.ActivityCompat;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.widget.TextView;public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String serviceString = Context.LOCATION_SERVICE; LocationManager locationManager = (LocationManager) getSystemService(serviceString); String provider = LocationManager.GPS_PROVIDER; if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } Location location = locationManager.getLastKnownLocation(provider); getLocationInfo(location); locationManager.requestLocationUpdates(provider, 2000, 0, locationListener); } private void getLocationInfo(Location location) { String latLongInfo; TextView locationText = (TextView) findViewById(R.id.label); if (location != null) { double latitude = location.getLatitude();//維度 double longitude = location.getLongitude();//經度 latLongInfo = "維度:" + latitude + "\n精度:" + longitude; }else{ latLongInfo = "No location found"; } locationText.setText("Your current position is:\n" + latLongInfo); } private final LocationListener locationListener = new LocationListener() { @Override public void onLocationChanged(Location location) { getLocationInfo(location); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { getLocationInfo(null); } @Override public void onProviderEnabled(String provider) { getLocationInfo(null); } @Override public void onProviderDisabled(String provider) { } };}
Android 定位服務(Location-Based Services)