Android中如何使用GPS获取位置信息?一个小Demo如下

GPS简介

Gobal Positioning System,全球定位系统,是美国在20世纪70年代研制的一种以人造地球卫星为基础的高精度无线电导航的定位系统,它在全球任何地方以及近地空间都能够提供准确的地理位置、车行速度及精确的时间信息;它是具有在海、陆、空进行全方位实时三维导航与定位功能的新一代卫星导航与定位系统。

中国用的定位系统是北斗卫星导航系统Beidou Navigation Satellite System,简称BDS,BDS、GPS、俄罗斯的GLONASS、欧盟的GALILEO是联合国卫星导航委员会已经认定的供应商。

手机的定位功能应用广泛,本章来学习GPS的应用开发。

GPS的常用API

GPS系统有三部分组成,卫星空间部分、地面监控部分和用户设备部分。

对于Android机来说,是用户设备部分,是GPS定位系统的接收机,也就是说GPS定位需要有硬件支持GPS功能。对于Android开发人员来说,通过LocationManager、LocationProvider、Location这三个API的一些方法就能开发出GPS应用。

程序的LocationManger对象不能直接创建,而是要通过Context.getSystemService方法获取

LocationManager locationManager= (LocationManager) getSystemService(Context.LOCATION_SERVICE);
List<String> allProviders = locationManager.getAllProviders();

通过询问chatGPT,整理出了这样的一个表格,LocationManger的方法以及作用如下:

方法名

返回值

作用

getLastKnownLocation(String provider)

Location

获取指定 provider 的最近一次位置信息

requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener)

void

注册位置监听器,以获取 provider 的位置更新。参数 minTime 和 minDistance 分别表示位置更新的最小时间间隔和最小距离间隔

removeUpdates(LocationListener listener)

void

取消位置监听器的注册

isProviderEnabled(String provider)

boolean

判断指定 provider 是否可用

addProximityAlert(double latitude, double longitude, float radius, long expiration, PendingIntent intent)

void

注册一个“地理围栏”,当设备进入指定半径的圆形区域时触发 intent

removeProximityAlert(PendingIntent intent)

void

取消“地理围栏”的注册

使用 LocationManager 时需要申请适当的权限,比如 ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION 权限。

还有一个API是LocationProvider,他不是Android中的类,而是 Android 系统中的一个抽象类,定义了位置提供者的标准接口,它的实现类用于提供位置信息。LocationProvider 的实现类可以通过系统服务 LocationManager 来获取。当应用程序请求获取位置信息时,LocationManager 会选择合适的位置提供者来获取位置信息,根据不同的需求选择不同的位置提供者。

方法名

返回值

作用

getName()

String

获取位置提供者(locationProvider)的名称

getAccuracy()

int

获取该位置提供者的精度

getPowerRequirement()

int

获取该位置提供者的电量消耗

hasMonetaryCost()

boolean

判断该位置提供者是否需要支付费用

requiresCell()

boolean

判断该位置提供者是否需要使用移动网络

requiresNetwork()

boolean

判断该位置提供者是否需要使用数据网络

requiresSatellite()

boolean

判断该位置提供者是否需要使用卫星

supportsAltitude()

boolean

判断该位置提供者是否支持海拔信息

supportsBearing()

boolean

判断该位置提供者是否支持方向信息

supportsSpeed()

boolean

判断该位置提供者是否支持速度信息

还有一个API是Location,Location 是 Android 中用于表示位置信息的类,它包含了经度、纬度、海拔、速度、方向等位置信息。Location 对象是由 LocationProvider 提供的,LocationManager 负责获取 LocationProvider 提供的位置信息,并将其封装成 Location 对象,然后提供给应用程序使用。方法如下:

方法名

返回值

作用

getLatitude()

double

获取该位置的纬度

getLongitude()

double

获取该位置的经度

getAltitude()

double

获取该位置的海拔

getAccuracy()

float

获取该位置的精度

getBearing()

float

获取该位置的方向

getSpeed()

float

获取该位置的速度

getTime()

long

获取该位置信息的时间戳

hasAccuracy()

boolean

判断该位置信息是否包含精度信息

hasAltitude()

boolean

判断该位置信息是否包含海拔信息

hasBearing()

boolean

判断该位置信息是否包含方向信息

hasSpeed()

boolean

判断该位置信息是否包含速度信息

需要注意的是,获取 Location 对象时可能会出现空值,因此在使用 Location 对象前需要先进行非空判断。另外,获取位置信息需要申请适当的权限,比如 ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION 权限。

上面三个API就是Android GPS定位支持的三个核心API。使用步骤如下:

1 获取系统的LocationManger对象。

2 使用LocationManger,通过指定的locationProvider来获取定位信息,定位信息由Location表示。

3 从Location对象中获取定位信息。

locationProvider

写一个简单的demo来获取当前系统所有的locationProvider

public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";private ListView listView;private LocationManager locationManager;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);listView = findViewById(R.id.list);locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);//获取所有的locationProvider名称List<String> allProviders = locationManager.getAllProviders();ArrayAdapter adapter=new ArrayAdapter(this, android.R.layout.simple_list_item_1,allProviders);listView.setAdapter(adapter);}
}

在真机上运行可以看到该系统上有如下四个LocationProvider

移动端通常通过WIFI、GPS、基站这三种方式来定位设备。

以下这四种provider分别来介绍一下

    public static final String NETWORK_PROVIDER = "network";public static final String GPS_PROVIDER = "gps";public static final String PASSIVE_PROVIDER = "passive";public static final String FUSED_PROVIDER = "fused";

NETWORK_PROVIDER:通过移动网络的基站或者 Wi-Fi 来获取地理位置;优点:只要有网络,就可以快速定位,室内室外都可;缺点:精确度不高;

GPS_PROVIDER:通过 GPS 来获取地理位置的经纬度信息;优点:获取地理位置信息精确度高;缺点:只能在户外使用,获取经纬度信息耗时,耗电;

PASSIVE_PROVIDER:被动接收更新地理位置信息,而不用自己请求地理位置信息。

PASSIVE_PROVIDER 返回的位置是通过其他 providers 产生的,可以查询 getProvider() 方法决定位置更新的由来,需要 ACCESS_FINE_LOCATION 权限,但是如果未启用 GPS,则此 provider 可能只返回粗略位置匹配;

FUSED_PROVIDER:已经被废弃了

通过名称获取指定的locationProvider

LocationProvider provider = locationManager.getProvider(LocationManager.GPS_PROVIDER);

使用GPS获取位置信息

代码如下:

public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";private LocationManager locationManager;private TextView showInfo;@RequiresApi(api = Build.VERSION_CODES.M)@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);showInfo = findViewById(R.id.show_location);requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION},0x123);}private void updateView(Location location) {if (location != null) {Log.d(TAG, "updateView: 222");String res = "实时位置:\n" +"经度:" + location.getLongitude() +"\n纬度:" + location.getLatitude() +"\n高度:" + location.getAltitude() +"\n速度:" + location.getSpeed()+ "\n方向:" + location.getBearing();showInfo.setText(res);} else {Log.d(TAG, "updateView: 111");showInfo.setText("");}}@SuppressLint("MissingPermission")@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == 0x123 && grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {//创建locationManger对象locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);//获取最新的定位信息Location lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);updateView(lastKnownLocation);//每隔三秒获取一次GPS信息locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 3000, 8f, new LocationListener() {@Overridepublic void onLocationChanged(@NonNull Location location) {updateView(location);}});}}
}

这里代码也很简单,我布局文件只写了一个textView来展示经纬度信息,首先在onCreate方法里动态申请权限。在Android6.0以上不仅仅要在声明文件里静态注册,还有动态申请,否则会出现安全异常。然后就是一个更新UI的方法,通过传入的location获取经纬度高度等信息。选择完获取权限后,会执行onRequestPermissionsResult回调函数,然后就是获取定位信息更新UI。

最后需要在声明文件里静态注册权限。

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

我获取到的是北京市内某地区的经纬度,把该程序和地图功能结合,就能反映出该经纬度在地图上的具体位置,即可开发出GPS导航系统。

室内WIFI定位

室内WIFI定位主要根据WIFI路由器所在的位置进行定位,主要应用于室内较小的空间的精准定位。

Android 9 添加了WiFi 室内定义功能(RTT),以下内容来自 developer.android.com

Android 9 添加了对 IEEE 802.11mc Wi-Fi 协议(也称为 Wi-Fi Round-Trip-Time (RTT))的平台支持,从而让您的应用可以利用室内定位功能。
在运行 Android 9 且具有硬件支持的设备上,应用可以使用 RTT API 来测量与附近支持 RTT 的 Wi-Fi 接入点 (AP) 的距离。 设备必须已启用位置服务并开启 Wi-Fi 扫描(在 Settings > Location 下),同时您的应用必须具有 ACCESS_FINE_LOCATION 权限。

设备无需连接到接入点即可使用 RTT。 为了保护隐私,只有手机可以确定与接入点的距离;接入点无此信息。

如果您的设备测量与 3 个或更多接入点的距离,您可以使用一个多点定位算法来预估与这些测量值最相符的设备位置。 结果通常精准至 1 至 2 米。

室内WIFI定位的管理器是WifiRttManager,获取方式如下,由于在Android9后才增加该功能,所以需要先判断。

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {WifiRttManager wifiRttManager= (WifiRttManager) getSystemService(Context.WIFI_RTT_RANGING_SERVICE);
}

获取到wifirttmanger对象后,可以用startRanging开始定位,该方法里有三个参数。

startRanging(@NonNull RangingRequest request, @NonNull Executor executor, @NonNull RangingResultCallback callback)

RangingRequest:该参数代表一个定位请求,该参数管理本次定位是基于哪个WIFI节点进行访问的

Executor:创建一个新的线程来执行WIFI定位,避免阻塞UI线程。

RangingResultCallback:定位成功或失败的时候触发该对象内的特定方法

写一个具体的案例来实现室内WIFI定位,代码如下:

public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";WifiRttManager mWifiRttManager;//定义监听WIFI状态改变的BroadcastReceiverpublic class WIfiChangeReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(intent.getAction())) {//开始执行wifi定位startWifiLoc();}}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//定义一个监听网络状态的改变 WIFI状态改变的intentFilterIntentFilter wifiFilter = new IntentFilter();wifiFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);wifiFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);wifiFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);registerReceiver(new WIfiChangeReceiver(), wifiFilter);}@SuppressLint("MissingPermission")private void startWifiLoc() {//获取wifi管理器WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);//判断是否支持室内wifi定位功能boolean hasRtt = getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT);Log.d(TAG, "startWifiLoc: 是否具有室内WIFI定位功能:" + hasRtt);//Android版本大于9才能使用if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {//获取室内WiFi定位管理器mWifiRttManager = (WifiRttManager) getSystemService(Context.WIFI_RTT_RANGING_SERVICE);RangingRequest request = new RangingRequest.Builder().addAccessPoints(wifiManager.getScanResults())//添加WiFi扫描结果.build();//创建RangingRequest对象Log.d(TAG, "startWifiLoc: request:"+request);//开始请求执行室内WIFI定位mWifiRttManager.startRanging(request, Executors.newCachedThreadPool(), new RangingResultCallback() {@Overridepublic void onRangingFailure(int i) {//WIFI定位出错执行的方法Log.d(TAG, "onRangingFailure:错误码是: "+i);}@Overridepublic void onRangingResults(@NonNull List<RangingResult> list) {//室内WiFi定位返回结果时触发for (RangingResult rr : list){Log.d(TAG, "onRangingResults:与 "+rr.getMacAddress()+" WIFI的距离是:"+rr.getDistanceMm());}}});}}}

运行后报错了

查询了一下原因是我设备硬件不支持WIFIRTT功能。

总结WIFI定位的步骤:

1 获取WifiRttManger对象

2 通过RangingRequest.Builder来创建对象,创建之前应该先添加WiFi扫描得到WiFi访问点的信息

3 调用WifiRttManger对象的startRanging方法

近距离警报

之前学习的API方法中有一个函数:

addProximityAlert(double latitude, double longitude, float radius, long expiration, PendingIntent intent)

代码:

public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";private LocationManager locationManager;@RequiresApi(api = Build.VERSION_CODES.M)@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 0x123);}@SuppressLint("MissingPermission")@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == 0x123 && grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);//定义靠近点的经纬度信息double lon = 116.00;double lat = 46.00;float radius = 500F; //定义半径500MIntent intent = new Intent(this, ProxAlertReciever.class);//将intent封装成pendingIntentPendingIntent pendingIntent = PendingIntent.getBroadcast(this, -1, intent, 0);//添加临近警告locationManager.addProximityAlert(lat, lon, radius, -1, pendingIntent);}}
}

注册一个广播监听变化:

public class ProxAlertReciever extends BroadcastReceiver {private static final String TAG = "ProxAlertReciever";@Overridepublic void onReceive(Context context, Intent intent) {boolean isEnter= intent.getBooleanExtra(LocationManager.KEY_PROXIMITY_ENTERING,false);if (isEnter){//靠近提示Log.d(TAG, "onReceive: 快靠近了!!");}else {Log.d(TAG, "onReceive: 离开了!!");}}
}

至此 Android中的GPS的就讲完了,想开发出具体的导航系统还要结合地图功能。

Android中如何使用GPS相关推荐

  1. xamarin android gps,如何使用Xamarin在Android中同步获取GPS位置更新?

    具体来说,我正在使用Xamarin.Forms进行C#开发,但是在本机Android方面工作,编写了GPS包装类,该类可以通过依赖注入在Xamarin.Forms方面使用.在大多数情况下,关于Andr ...

  2. android网络获取经纬,Android中透过GPS或NetWork获取当前位置的经纬度

    Android中通过GPS或NetWork获取当前位置的经纬度 private double latitude=0.0; private double longitude =0.0; Location ...

  3. android获取当前位置经纬度,Android中通过GPS或NetWork获取当前位置的经纬度

    今天在Android项目中要实现一个通过GPS或NetWork来获取当前移动终端设备的经纬度功能.要实现该功能要用到Android Framework 中的 LocationManager 类.下面我 ...

  4. Android中网络使用

    Android中判断网络连接是否可用 一.判断网络连接是否可用 public static boolean isNetworkAvailable(Context context) { Connecti ...

  5. Android中的那些权限

    随着智能手机的普及,越来越多各式各样的应用和服务出现在手机平台上.这些应用和服务要访问手机上的 资源,就牵涉到权限问题.手机又是一个非常敏感的平台,涉及到用户的很多个人信息,隐私等等,在这种背景 下权 ...

  6. android中几种定位方式详解

    目录 前言: 1.GPS定位 2.NETWORK定位 3.AGPS定位 4.基站定位 5.WIFI定位 6.混合定位 目前,移动端大致通过三种方式来进行设备定位:GPS.基站.wifi.本文就详细的讲 ...

  7. Android中获取当前位置的使用步骤

    在Android中得到当前位置的步骤 1.在AndroidManifest.xml中声明权限 android.permission.ACCESS_FINE_LOCATION(或者android.per ...

  8. 求android 中串口的发送接收数据代码

    RT,求高手帮忙! 就是 /dev/ttyS0 和/dev/ttyS1 两个设备的通信问题.. 同求~ 这个是不是需要串口驱动啊?最近正在搞这个串口通信的案子,头疼 同样也没有搞出来,老是报:不能扫描 ...

  9. android 安全 权限,[原创]Android 中的那些权限

    [原创]Android 中的那些权限 2013-5-9 20:04 4610 [原创]Android 中的那些权限 2013-5-9 20:04 4610 1.        随着智能手机的普及,越来 ...

最新文章

  1. python生成word目录_Word&Python-创建目录
  2. Liux技巧总结之--解压各种文件
  3. php无表单上传文件,php – 如何使用没有实体类的表单上传文件
  4. 四叶草社交平台——十天冲刺(10)
  5. docker 分布式管理群集_Coolpy7分布式物联网MQTT集群搭建
  6. 用android制作一个记事本app_用扁平化呈现一个天气APP
  7. “带货”的逻辑:直播电商产业链研究报告
  8. python调用高德地图api 可视化_Python:利用高德地图API实现找房
  9. mongodb连接池 php,node.js,mongodb_nodejs使用mongodb连接池,node.js,mongodb - phpStudy
  10. Github操作指南
  11. Atitit. 有限状态机 fsm 状态模式
  12. win7开机动画_win7系统怎么修改开机动画 win7系统开机动画修改方法
  13. 网页打印计算机死机,调用网络打印就死机
  14. 考研数一英语二计算机,考研常识 | 我是考英语一还是英语二?数一二三都有什么区别...
  15. 使用稿定设计如何给制作好的视频加音乐?
  16. c课设:快递包裹管理系统
  17. 10分钟用Python制作恋爱日志
  18. 民宿逐渐兴起后 旅游会不会是90后创业新方向?
  19. 搭建云平台 1 Day 虚拟机安装(超详细)
  20. 滴滴出行A/B测试数据分析

热门文章

  1. python爬取问卷星内容_python问卷星爬虫bug求助
  2. 2021华为软件精英挑战赛初赛baseline
  3. Win11控制面板没有realtek怎么办?
  4. 【MySQL】数据库服务器硬件优化与实战详解(调优篇)(实战篇)(MySQL专栏启动)
  5. APP定制开发要做什么准备-甲由科技为你解答
  6. 华为交换机认证aaa模式创建本地用户
  7. 从QQ空间技术分享中收获的几点总结
  8. 超透镜消色差方法理解与总结
  9. 水深6到9米有鱼吗_【钓鱼技巧】秋季野钓是钓深水,还是浅水好?三招选择野钓的水深|野钓|浅水|浅水区|作钓...
  10. uni-app卖座电影多端开发纪实(一):创建项目