发布时间:2025-12-10 11:36:17 浏览次数:4
在Android开发中常常须要用到定位功能,尤其是依赖于地理位置功能的应用。大家首先想到的是使用百度地图、高德地图提供的sdk,但是在只须要经纬度或者城市、街道地址等信息并不须要提供预览地图时我们考虑使用Android系统提供的API来实现。
Android SDK 提供了 android.location 包和 Google Maps API 支持位置服务功能,开发人员可以方便地开发自己的位置服务应用程序。
android 定位一般有四种方法,这四种方式分别是:GPS定位,WIFI定准,基站定位,AGPS定位
在开发过程中主要使用android.location包中的LocationManager和LocationProviders对象。
LocationManager 类用于管理 Android 用户位置服务信息,提供确定用户位置的 API,通过这个类可以实现定位、跟踪和目标趋近等功能。
LocationManager 对象可以完成以下三个方面的任务:
从用户的位置查询所有可用的 LocationProvider 列表。
从特定的 LocationProvider 周期性获取用户当前位置的功能。
当用户位置接近某个特定区域时,启动相关任务。
⭐️ LocationManager 对象不能直接实例化,可以通过 Context.getSystemService(Context. LOCATION_SERVICE) 方法获得。
常用方法:
boolean addGpsStatusListener(GpsStatus.Listener listener):添加一个监听GPS状态的监听器
void removeGpsStatusListener(GpsStatus.Listener listener):删除Gps状态监听器
List getAllProviders():获得所有LocationProvider列表
String getBestProvider(Criteria criteria,Boolean enabldOny):根据 criteria 返回最合适的 LocationProvider,其中 criteria 指定了一系列条件
Location getLastKnownLocation (String provider):获取缓存中的位置信息, 该方法不会发起监听,返回的是上一次的位置信息,但此前如果没有位置更新的话,返回的位置信息可能是错误的
LocationProvider getProvider (String name):获得指定名称的 LocationProvider
List getProviders (boolean enabledOnly):获得可用的 LocationProvider 列表
addProximityAlert (double latitude, double longitude, float radius, long expiration, PendingIntent intent):添加一个邻近警告
removeProximityAlert (PendingIntent intent):删除趋近警告
void requestLocationUpdates(String provider, long minTime, float minDistance, PendingIntent intent): 通过指定的LoactionProvider周期性地获取定位信息,并通过intent启动相应的组件
void requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener): 通过指定的LocationProvider周期性地获取定位信息,并触发listener所对应的触发器3
requestSingleUpdate(String provider, LocationListener listener, Looper looper):获取一次定位结果,如果不想一直监听位置信息,那么可以用requestSingleUpdate来实现只请求一次定位,该方法也要在主线程上执行
isProviderEnabled(String provider):判断provider是否可用
⭐️ LocationProvider 为位置提供者的抽象类,位置提供者提供手机设备周期性的地理位置报告。
常用方法:
? int getAccuracy():获取LocationProvider提供位置信息的精度
? String getName():获得LocationProvider的名称
? int getPowerRequirement():获得LocationProvider 对电源的需求
? boolean hasMonetaryCost():获取当前LocationProvider 是免费的还是收费的
? boolean meetsCriteria(Criteria criteria):确定当前 LocationProvider 是否符合特定条件
? boolean requiresCell():LocationProvider定位是否需要访问基站网络
? boolean requiresNetwork():LocationProvider定位是否需要 Internet 网络数据
?boolean requiresSatellite():LocationProvider定位是否需要获取卫星数据
? boolean supportsAltitude():LocationProvider提供的位置信息是否包含高度信息
? boolean supportsBearing():是否能够提供方向信息
? boolean supportsAltitude():LocationProvider是否能够提供速度信息
⭐️ Location它就是一个代表位置信息的抽象类,记录了经纬度、海拔高度、获取坐标时间、速度、方位等
⭐️ 不过很多时候得到的Location对象为null;实时动态坐标可以在监听器locationListener的onLocationChanged(Location location)方法中来获取。
常用方法:
?float getAccuracy():获得定位信息的精度
?double getAltitude():获得定位信息的高度
?float getBearing():获得定位信息的方向
?double getLatitude():获得定位信息的纬度
?double getLongitude():获得定位信息的精度
?String getProvider():获得提供该定位信息的LocationProvider
?float getSpeed():获得定位信息的速度
?boolean hasAccuracy ():判断该定位信息是否含有精度信息
用于监听位置(包括GPS、网络、基站等所有提供位置的)变化,监听设备开关与状态。实时动态获取位置信息,首先要实现该接口,在相关方法中添加实现功能的代码,实现该接口可以使用内部类或者匿名实现。
注册监听:LocationManger.requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener)。
?provider:注册的provider的名称,可以是GPS_PROVIDER等。
?minTime:通知间隔的最小时间,单位是毫秒。系统可能为了省电而延长该时间。
?minDistance:更新通知的最小变化距离,单位是米。
?listener:用于处理通知的监听器。
n 使用完之后需要在适当的位置移除监听:LocationManager .removeUpdates(LocationListener listener)
?onLocationChanged(Location location):当位置发生变化的时候会自动调用该方法,参数location记录了最新的位置信息(经纬度)。Location表示位置发生变化后的新位置。
?onStatusChanged(String provider, int status, Bundle extras):当位置提供者的状态发生改变(可用到不可用、不可用到可用)时自动调用该方法;参数provider为位置提供者的名称,status为状态信息:OUT_OF_SERVICE(0,无服务)、AVAILABLE(2,provider可用) 、TEMPORARILY_UNAVAILABLE(1,不可用),extras为附加数据:key/value,如satellites;
?onProviderEnabled(String provider):当provider可用时被触发,比如定位模式切换到了使用精确位置时GPSProvider就会回调该方法;
?onProviderDisabled(String provider):当provider不可用时被触发,比如定位模式切换到了使用使用网络定位时GPSProvider就会回调该方法。
n 使用方法与locationListener接口类似,先实现接口并创建对象,实现接口中的方法:onGpsStatusChanged(int event);在方法中实现对卫星状态信息变化的监听,根据event的类型编写逻辑代码。
n 创建对象后再注册监听:LocationManager .addGpsStatusListener(GpsStatus.Listener listener);使用后在合适的位置释放监听:LocationManager .removeGpsStatusListener(GpsStatus.Listener listener)。
创建LocationProvider对象时会使用到该类。定位信息提供者会根据精度、电量、是否提供高度、速度、方位、服务商付费等信息进行排序选择定位提供者。
(1)配置权限:
添加如下权限
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />是粗略位置,该权限只针对NETWORK_PROVIDER。<uses-permission android:name="android.permission..ACCESS_FINE_LOCATION" />是精确位置,如果使用GPS_PROVIDER或者同时使用GPS_PROVIDER和NETWORK_PROVIDER,需声明该权限,它对于这两个provider都是有效的;(2)获取LocationManager类型对象
(3)获取LocationProvider
根据设备的不同可以使用不同的定位技术来实现位置服务,也就是获取不同的 LocationProvider,以下是 3 种获取LocationProvider 实例的方法。
getProvider(LocationManager.GPS_PROVIDER)
根据 LocationManager 中的静态常量 GPS_PROVIDER 和 NETWORK_PROVIDER 来分别获得 GPS Provider 和 Network Provider
GPS_PROVIDER:这个就是手机里有GPS芯片,然后利用该芯片就能利用卫星获得自己的位置信息。可是在室内,GPS定位基本没用,非常难定位的到。
优点:获取地理位置信息精确度高;
缺点:只能在户外使用,获取经纬度信息耗时,耗电;
NETWORK_PROVIDER:这个就是利用网络定位,一般是利用手机基站和WIFI节点的地址来大致定位位置,这样的定位方式取决于server,即取决于将基站或WIFI节点信息翻译成位置信息的server的能力。因为眼下大部分Android手机没有安装google官方的location manager库。大陆网络也不同意。即没有server来做这个事情,自然该方法基本上没法实现定位。
优点:只要有网络,就可以快速定位,室内室外都可;
缺点:精确度不高;
PASSIVE_PROVIDER:被动定位方式。被动接收更新地理位置信息,而不用自己请求地理位置信息。 PASSIVE_PROVIDER 返回的位置是通过其他 providers 产生的,可以查询 getProvider() 方法决定位置更新的由来,需要 ACCESS_FINE_LOCATION 权限,但是如果未启用 GPS,则此 provider 可能只返回粗略位置匹配;
这个意思也比較明显。就是用现成的,当其它应用使用定位更新了定位信息。系统会保存下来。该应用接收到消息后直接读取就能够了。比方假设系统中已经安装了百度地图,高德地图(室内能够实现精确定位)。你仅仅要使用它们定位过后。再使用这样的方法在你的程序肯定是能够拿到比較精确的定位信息。
通过调用 locationManager.getProviders(true) 方法就可以获得可利用的 LocationProvider 实例列表
?每个 LocationProvider 都有一个条件集合,以便于应用程序可以选择合适的位置提供者。
?例如有的 LocationProvider 要求设备本身具有 GPS 模块,并且要求看见卫星的数量,有的要求手机设备能够接入 Internet 或者特定网络等。Criteria 类被用于为 LocationProvider 设置相关条件。
?Criteria 对象封装了获得 LocationProvider 实例的条件,可以根据指定的 Criteria 条件来过滤 LocationProvider 列表,以得到符合条件的 LocationProvider 实例。
– Criteria 的常用方法
⭐️isAltitudeRequired():返回 Provider 是否需要高度信息
⭐️isBearingRequired():返回 Provider 是否需要方向信息
⭐️isSpeedRequired():返回 Provider 是否需要速度信息
⭐️isCostAllowed():标识是否允许产生费用
⭐️setAccuracy(int accuracy):设置 Provider 的精确度
⭐️setAltitudeRequired (boolean altitudeRequired):设置 Provider 是否需要高度信息
⭐️setBearingRequired (boolean bearingRequired):设置 Provider 是否需要方位信息
⭐️setSpeedRequired (boolean speedRequired):设置 Provider 是否需要速度信息
⭐️setCostAllowed (boolean cost Allowed):设置是否需要产生费用
⭐️getAccuracy():获取位置信息的准确度
(4)实现LocationListener接口:可以采用内部类(MyLocationListener)或匿名类方式实现,重写接口方法
(5)使用完释放监听:
mLocationManager.removeUpdates(mLocationListener);
该方法执行的位置需要特别注意,如果是在Activity对象中,则需要考虑Activity的生命周期,onPause方法中比较合适,因为onStop、onDestroy两个方法在异常情况下不会被执行。
(6)如果需要监听GPS卫星状态,则需要实现GpsStatus.Listener接口,并创建对象、添加监听、使用完后释放监听
private class MyGpsStatusListener implements GpsStatus.Listener;addProximityAlert(double latitude,double longitude,float radius,long expiration,PendingIntent intent)
⭐️ latitude指定固定点的经度
⭐️ longitude指定固定点的纬度
⭐️ radius指定半径长度
⭐️ expiration指定经过多少毫秒后该临近警告就会过期失效,-1 表示永不过期
⭐️ intent该参数指定临近该固定点时触发该 intent 对应的组件
Android 9 中的 WLAN 往返时间 (RTT) 功能允许设备测量与其他支持设备的距离:无论它们是接入点 (AP) 还是 WLAN 感知对等设备(如果设备支持 WLAN 感知功能)。此功能基于 IEEE 802.11mc 协议,使应用能够使用准确性更高的定位功能和增强的感知功能。
用户可以利用 WLAN RTT(往返时间)API 提供的 WLAN 定位功能,测量距附近支持 RTT 的 WLAN 接入点和 WLAN 感知对等设备的距离。
请求发出设备无需连接到接入点即可通过 WLAN RTT 测量距离。为维护隐私,只有发出请求的设备能够确定距接入点的距离,接入点没有此信息。前台应用执行 WLAN RTT 操作不受限制,但后台应用执行此类操作时会受限。
1、测距请求发出设备的硬件必须实现 802.11mc FTM 标准。
2、测距请求发出设备必须运行 Android 9(API 级别 28)或更高版本的操作系统。
3、测距请求发出设备必须启用位置服务并打开 WLAN 扫描(Settings > Location)。
4、测距请求发出设备必须拥有 ACCESS_FINE_LOCATION 权限。
5、接入点必须实现 IEEE 802.11mc FTM 标准。
⭐️ 设备上可能存在 WLAN RTT,但由于用户已禁用 WLAN,该功能目前或不可用。如果 SoftAP 或网络共享处于使用状态,则某些设备可能不支持 WLAN RTT,具体视设备的硬件和固件功能而定。
⭐️ 如要检查 WLAN RTT 当前是否可用,请调用 isAvailable()。
⭐️ WLAN RTT 的可用性随时可能发生变化。所以应注册一个 BroadcastReceiver,以接收 ACTION_WIFI_RTT_STATE_CHANGED(系统会在可用性发生变化时发送该内容)。当应用收到广播 Intent 时,其应检查可用性的当前状态,并对其行为进行相应调整。
IntentFilter filter =new IntentFilter(WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED);BroadcastReceiver myReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) { if (wifiRttManager.isAvailable()) { … } else { … }}};context.registerReceiver(myReceiver, filter);通过指定请求范围的 AP 或 WLAN 感知对等设备的列表,即可创建测距请求 (RangingRequest)。可以在单个测距请求中指定多个接入点或 WLAN 感知对等设备,然后测量并返回与所有设备的距离。
请求可以使用 addAccessPoint() 方法指定要测量距离的接入点:
接入点由其 ScanResult 对象标识,该对象可通过调用 WifiManager.getScanResults() 获得。可以使用 addAccessPoints(List) 批量添加多个接入点。
可以通过以下两种途径添加 WLAN 感知对等设备:使用 addWifiAwarePeer(MacAddress 对等点) 方法利用请求的 MAC 地址,或者使用 addWifiAwarePeer(PeerHandle 对等点) 方法利用请求的 PeerHandle。
应用使用 WifiRttManager.startRanging() 方法发出测距请求,并提供以下内容:用于指定操作的 RangingRequest、用于指定回调上下文的 Executor,以及用于接收结果的 RangingResultCallback。
测距操作以异步方式执行;测距结果在 RangingResultCallback 的某个回调中返回:
如果整个测距操作失败,则会触发 onRangingFailure 回调,并返回 RangingResultCallback 中描述的状态代码。如果该服务当时出于某些原因(例如 WLAN 遭到禁用、应用请求的测距操作过多并受到限制,或者存在权限问题)无法执行测距操作,则可能会发生此类失败。
测距操作完成后,会触发 onRangingResults 回调,并返回与请求列表匹配的结果列表(每个请求匹配一个结果)。结果的顺序不一定与请求的顺序一致。请注意,测距操作可能已经完成,但每个结果仍有可能提示该特定测量失败,
onRangingResults 回调返回的每个结果均由 RangingResult 对象指定。请对每个请求执行以下操作。
根据创建 RangingRequest 时提供的信息来识别请求。该信息通常是在 ScanResult中提供的 MAC 地址,用于识别接入点。可以使用 getMacAddress()方法从测距结果中获得 MAC 地址。
测距结果列表的顺序可能与测距请求中指定的对等设备(接入点)的顺序不同,因此应使用 MAC 地址而非结果的顺序来识别对等设备。
确定每个测量是否成功
如要确定测量是否成功,请使用 getStatus() 方法。STATUS_SUCCESS 以外的任何值都表示失败。失败意味着此结果的所有其他字段(上述请求标识除外)均为无效字段,相应的 get* 方法也将失败,并显示 IllegalStateException 异常。
对于每个成功的测量,可以使用相应的 get 方法检索结果值:
距离(单位为毫米)和测量的标准偏差:getDistanceMm()和getDistanceStdDevMm()
用于测量的数据包的 RSSI:getRssi()
测量所用时间(以毫秒为单位;表示自启动以来的时间):getRangingTimestampMillis()
尝试的测量个数和成功的测量个数(以及距离测量的依据):getNumAttemptedMeasurements()和
getNumSuccessfulMeasurements()