废话不多说,直接开始说说与实现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, 0 , 0 , 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, 0 , 0 , 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实现定位功能。