閱讀836 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Android定位功能

廢話不多說,直接開始說說與實現Android定位有關的API吧。

  這些API都在android.location包下,一共有三個接口和八個類。它們配合使用即可實現定位功能。

 

  三個接口:

  GpsStatus.Listener: 這是一個當GPS狀態發生改變時,用來接收通知的接口。

  GpsStatus.NmeaListener: 這是一個用來從GPS裏接收Nmea-0183(為海用電子設備製定的標準格式)信息的接口。

  LocationListener: 位置監聽器,用於接收當位置信息發生改變時從LocationManager接收通知的接口。

 

  八個類:

  Address: 描述地址的類,比如:北京天安門

  Criteria: 用於描述Location Provider標準的類,標準包括位置精度水平,電量消耗水平,是否獲取海拔、方位信息,是否允許接收付費服務。

  GeoCoder: 用於處理地理位置的編碼。

  GpsSatellite: 和GpsStatus聯合使用,用於描述當前GPS衛星的狀態。

  GpsStatus: 和GpsStatus.Listener聯合使用,用於描述當前GPS衛星的狀態。

  Location: 用於描述位置信息。

  LocationManager: 通過此類獲取和調用係統位置服務

  LocationProvider: 用於描述Location Provider的抽象超類,一個LocationProvider應該能夠周期性的報告當前設備的位置信息。

 

  這裏通過一個代碼示例,演示一下如何實現定位。

  首先,在AndroidManifest.xml清單文件裏需要加入ACCESS_FINE_LOCATION權限

1 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
其次,實現代碼如下:
001 package com.test;
002   
003  import java.io.IOException;
004  import java.util.List;
005   
006  import android.app.Activity;
007  import android.location.Address;
008  import android.location.Criteria;
009  import android.location.Geocoder;
010  import android.location.Location;
011  import android.location.LocationListener;
012  import android.location.LocationManager;
013  import android.os.Bundle;
014  import android.util.Log;
015  import android.widget.Toast;
016   
017  public class MainActivity extends Activity {
018      @Override
019      public void onCreate(Bundle savedInstanceState) {
020         super.onCreate(savedInstanceState);
021         setContentView(R.layout.main);
022          
023         //獲取到LocationManager對象
024         LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
025         //創建一個Criteria對象
026         Criteria criteria = new Criteria();
027         //設置粗略精確度
028         criteria.setAccuracy(Criteria.ACCURACY_COARSE);
029         //設置是否需要返回海拔信息
030         criteria.setAltitudeRequired(false);
031         //設置是否需要返回方位信息
032         criteria.setBearingRequired(false);
033         //設置是否允許付費服務
034         criteria.setCostAllowed(true);
035         //設置電量消耗等級
036         criteria.setPowerRequirement(Criteria.POWER_HIGH);
037         //設置是否需要返回速度信息
038         criteria.setSpeedRequired(false);
039   
040         //根據設置的Criteria對象,獲取最符合此標準的provider對象
041         String currentProvider = locationManager.getBestProvider(criteria, true);
042         Log.d("Location""currentProvider: " + currentProvider);
043         //根據當前provider對象獲取最後一次位置信息
044         Location currentLocation = locationManager.getLastKnownLocation(currentProvider);
045         //如果位置信息為null,則請求更新位置信息
046         if(currentLocation == null){
047             locationManager.requestLocationUpdates(currentProvider, 00, locationListener);
048         }
049         //直到獲得最後一次位置信息為止,如果未獲得最後一次位置信息,則顯示默認經緯度
050         //每隔10秒獲取一次位置信息
051         while(true){
052             currentLocation = locationManager.getLastKnownLocation(currentProvider);
053             if(currentLocation != null){
054                 Log.d("Location""Latitude: " + currentLocation.getLatitude());
055                 Log.d("Location""location: " + currentLocation.getLongitude());
056                 break;
057             }else{
058                 Log.d("Location""Latitude: " 0);
059                 Log.d("Location""location: " 0);
060             }
061             try {
062                 Thread.sleep(10000);
063             catch (InterruptedException e) {
064                  Log.e("Location", e.getMessage());
065             }
066         }
067          
068         //解析地址並顯示
069         Geocoder geoCoder = new Geocoder(this);
070         try {
071             int latitude = (int) currentLocation.getLatitude();
072             int longitude = (int) currentLocation.getLongitude();
073             List<Address> list = geoCoder.getFromLocation(latitude, longitude, 2);
074             for(int i=0; i<list.size(); i++){
075                 Address address = list.get(i);
076                 Toast.makeText(MainActivity.this, address.getCountryName() + address.getAdminArea() + address.getFeatureName(), Toast.LENGTH_LONG).show();
077             }
078         catch (IOException e) {
079             Toast.makeText(MainActivity.this,e.getMessage(), Toast.LENGTH_LONG).show();
080         }
081          
082      }
083       
084      //創建位置監聽器
085      private LocationListener locationListener = new LocationListener(){
086          //位置發生改變時調用
087          @Override
088          public void onLocationChanged(Location location) {
089              Log.d("Location""onLocationChanged");
090              Log.d("Location""onLocationChanged Latitude" + location.getLatitude());
091                   Log.d("Location""onLocationChanged location" + location.getLongitude());
092          }
093   
094          //provider失效時調用
095          @Override
096          public void onProviderDisabled(String provider) {
097              Log.d("Location""onProviderDisabled");
098          }
099   
100          //provider啟用時調用
101          @Override
102          public void onProviderEnabled(String provider) {
103              Log.d("Location""onProviderEnabled");
104          }
105   
106          //狀態改變時調用
107          @Override
108          public void onStatusChanged(String provider, int status, Bundle extras) {
109              Log.d("Location""onStatusChanged");
110          }
111      };
112  }

由於代碼裏的Criteria對象對位置精度要求並不高,所以一般會返回“network”作為provider,而基於network的定位往往會存在一定的位置偏差,這對於需要精確定位的應用程序來說,顯然不合要求。這時,需要則需要用到基於GPS的定位方法了

在實現GPS定位前,先了解一下GPS的部分特性:

  1. GPS定位需要依靠3顆或3顆以上的衛星。

  2. GPS定位受環境影響較大,在晴朗的空地上,較容易搜索到衛星,而在室內通常是無法搜索到衛星的。

  3. GPS定位需要使用GPS功能模塊,而GPS功能模塊的耗電量是巨大的。

  在Android係統中,實現GPS定位的思路應該是:

  1. 獲取GPS的Location Provider。

  2. 講此Provider傳入到requestLocationUpdates()方法,讓Android係統獲知搜索位置方式。

  3. 創建實現了GpsStatus.Listener接口的對象,重寫onGpsStatusChanged()方法,向LocationManager添加次監聽器,檢測衛星狀態。(可選步驟)

001 public class MainActivity extends Activity {
002      private LocationManager locationManager;
003      private GpsStatus gpsstatus;
004      @Override
005      public void onCreate(Bundle savedInstanceState) {
006         super.onCreate(savedInstanceState);
007         setContentView(R.layout.main);
008          
009         //獲取到LocationManager對象
010         locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
011          
012         //根據設置的Criteria對象,獲取最符合此標準的provider對象
013         String currentProvider = locationManager.getProvider(LocationManager.GPS_PROVIDER).getName();
014          
015         //根據當前provider對象獲取最後一次位置信息
016         Location currentLocation = locationManager.getLastKnownLocation(currentProvider);
017         //如果位置信息為null,則請求更新位置信息
018         if(currentLocation == null){
019             locationManager.requestLocationUpdates(currentProvider, 00, locationListener);
020         }
021         //增加GPS狀態監聽器
022         locationManager.addGpsStatusListener(gpsListener);
023          
024         //直到獲得最後一次位置信息為止,如果未獲得最後一次位置信息,則顯示默認經緯度
025         //每隔10秒獲取一次位置信息
026         while(true){
027             currentLocation = locationManager.getLastKnownLocation(currentProvider);
028             if(currentLocation != null){
029                 Log.d("Location""Latitude: " + currentLocation.getLatitude());
030                 Log.d("Location""location: " + currentLocation.getLongitude());
031                 break;
032             }else{
033                 Log.d("Location""Latitude: " 0);
034                 Log.d("Location""location: " 0);
035             }
036             try {
037                 Thread.sleep(10000);
038             catch (InterruptedException e) {
039                  Log.e("Location", e.getMessage());
040             }
041         }
042      }
043       
044      private GpsStatus.Listener gpsListener = new GpsStatus.Listener(){
045          //GPS狀態發生變化時觸發
046          @Override
047          public void onGpsStatusChanged(int event) {
048              //獲取當前狀態
049              gpsstatus=locationManager.getGpsStatus(null);
050              switch(event){
051                  //第一次定位時的事件
052                  case GpsStatus.GPS_EVENT_FIRST_FIX:
053                      break;
054                  //開始定位的事件
055                  case GpsStatus.GPS_EVENT_STARTED:
056                      break;
057                  //發送GPS衛星狀態事件
058                  case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
059                      Toast.makeText(MainActivity.this"GPS_EVENT_SATELLITE_STATUS", Toast.LENGTH_SHORT).show();
060                      Iterable<GpsSatellite> allSatellites = gpsstatus.getSatellites();  
061                      Iterator<GpsSatellite> it=allSatellites.iterator();
062                      int count = 0;
063                      while(it.hasNext())  
064                      {  
065                          count++;
066                      }
067                      Toast.makeText(MainActivity.this"Satellite Count:" + count, Toast.LENGTH_SHORT).show();
068                      break;
069                  //停止定位事件
070                  case GpsStatus.GPS_EVENT_STOPPED:
071                      Log.d("Location""GPS_EVENT_STOPPED");
072                      break;
073              }
074          }
075      };
076       
077       
078      //創建位置監聽器
079      private LocationListener locationListener = new LocationListener(){
080          //位置發生改變時調用
081          @Override
082          public void onLocationChanged(Location location) {
083              Log.d("Location""onLocationChanged");
084          }
085   
086          //provider失效時調用
087          @Override
088          public void onProviderDisabled(String provider) {
089              Log.d("Location""onProviderDisabled");
090          }
091   
092          //provider啟用時調用
093          @Override
094          public void onProviderEnabled(String provider) {
095              Log.d("Location""onProviderEnabled");
096          }
097   
098          //狀態改變時調用
099          @Override
100          public void onStatusChanged(String provider, int status, Bundle extras) {
101              Log.d("Location""onStatusChanged");
102          }
103      };
104  }

通過以上代碼中的注釋部分,可以清晰的知道Android定位功能裏相關方法的具體含義。希望對大家有用。

  另外,因為GPS的自身特性,此代碼在室內幾乎無法定位,所以建議再真正的實際項目裏,至少使用network和GPS兩種不同的Location Provider實現定位功能。


最後更新:2017-04-03 22:15:39

  上一篇:go 蘋果是不是低估了三星所帶來的威脅?
  下一篇:go 如何學會 600 多種編程語言