阅读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 多种编程语言