前言
因为项目中经常会遇到要上传一系列设备信息的功能,为了方便使用,所以就拆分成以下系列文章来单独介绍如何获取各类设备信息
- 手机运营商获取
- AndroidID、IMEI、OAID获取
- 地理位置信息经纬度获取
- 公网IP地址获取:移动网络IP、Wifi IP
- Build类获取相关设备信息
- 屏幕相关信息:密度、物理尺寸获取
- BuildConfig获取的一系列基础信息
- UA、网络状态…等持续更新
1. 基础学习
在介绍之前,先讲一些获取经纬度信息相关的基础知识
1.1 LocationManager
位置管理器
想要获取经纬度信息,主要是通过LocationManager这个类,该类不能直接new,需要通过如下方式获取
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
讯享网
获取位置信息是通过该类的getLastKnownLocation(provider:String)方法,可以看到,使用此方法需要我们传递个provider,位置提供器。
1.2 LocationProvider
位置提供器
位置提供器一共有三种
NETWORK_PROVIDER:通过蜂窝塔(基站)和WIFI接入点来获取GPS_PROVIDER:通过GPS的方式获取PASSIVE_PROVIDER:被动的通过其他程序获取经纬度
讯享网locationManager.getProviders(true)
该方法会返回一个手机所支持的位置提供器集合
1.3 精度
假如我们通过以上三种provider都能获取到Location,那么选哪种作为经纬度最合适呢?
Location有getAccuracy()方法来获取精度,看官方getAccuracy()的解释:
/ * Get the estimated horizontal accuracy of this location, radial, in meters. * * <p>We define horizontal accuracy as the radius of 68% confidence. In other * words, if you draw a circle centered at this location's * latitude and longitude, and with a radius equal to the accuracy, * then there is a 68% probability that the true location is inside * the circle. * * <p>This accuracy estimation is only concerned with horizontal * accuracy, and does not indicate the accuracy of bearing, * velocity or altitude if those are included in this Location. * * <p>If this location does not have a horizontal accuracy, then 0.0 is returned. * All locations generated by the {@link LocationManager} include horizontal accuracy. */
简单的理解就是:
若以该经纬度作为圆心,精度作为半径画圆,那么真实的位置落在该圆内的概率为68%。因为落在该圆内的概率是固定的68%,那么肯定是圆的半径即精度越小,就越准确。所以我们选取getAccuracy()返回值最小的那个provider。
1.4 LocationListener
有时候可能会因为没有网或者在室内,通过以上方式获取到的location均为null,那么此时我们可以开启位置信息的连续监听,当时间超过设定的秒数或者位置移动超过设定的米数时,更新位置信息。
讯享网private var locationListener: LocationListener = object : LocationListener {
override fun onLocationChanged(location: Location) {
Log.i(TAG, "onLocationChanged: 经纬度发生变化") //调用更新位置 updateToNewLocation(location) } override fun onProviderDisabled(provider: String) {
updateToNewLocation(null) Log.i(TAG, "onProviderDisabled: ") } override fun onProviderEnabled(provider: String) {
Log.i(TAG, "onProviderEnabled: ") } }
locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 60000.toLong(), //每隔1分钟重新获取一次 8.toFloat(), //移动距离超过8米重新获取一次 locationListener )
2. 所需权限
| 权限 | 说明 |
|---|---|
| INTERNET | 允许使用网络 |
| ACCESS_FINE_LOCATION | 允许使用GPS定位 |
| ACCESS_COARSE_LOCATION | 允许使用WIFI热点或基站来获取粗略的定位 |
3. 获取步骤
3.1 申请权限
只有申请到了ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION后,才可以进行下一步获取经纬度信息的操作,这里不多讲,完整代码如下:
讯享网class LocationActivity : AppCompatActivity() {
companion object {
const val LOCATION_REQUEST_CODE = 1 const val LISTENER_REQUEST_CODE = 2 } override fun onCreate(savedInstanceState: Bundle?) {
//申请权限 if (PermissionUtil.requestPermission(LOCATION_REQUEST_CODE, permissionList.toList(), this)) {
//获取经纬度信息 getLocationInfo() } } / * 权限申请回调 */ override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults) when (requestCode) {
//LOCATION_REQUEST_CODE权限申请 LOCATION_REQUEST_CODE -> {
if (PermissionUtil.verifyResult(grantResults, this)) {
getLocationInfo() } else {
Toast.makeText(this, "没有权限", Toast.LENGTH_SHORT).show() } } } } }
object PermissionUtil {
/ * 验证是否有权限,没有则申请 */ fun requestPermission(requestCode: Int, permissionList: List<String>, context: Context): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//没有同意需要申请的权限 val requestPermissionList = mutableListOf<String>() for (permission in permissionList) {
if (ContextCompat.checkSelfPermission( context, permission ) != PackageManager.PERMISSION_GRANTED ) {
requestPermissionList.add(permission) } } if (requestPermissionList.size > 0) {
ActivityCompat.requestPermissions( context as Activity, requestPermissionList.toTypedArray(), requestCode ) return false } else {
return true } } else {
return true } } / *验证权限申请的结果 */ fun verifyResult(grantResults: IntArray,context: Context): Boolean {
if (grantResults.isNotEmpty()) {
for (result in grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(context, "必须同意所有权限才能使用该功能", Toast.LENGTH_SHORT).show() return false } } return true } else {
Toast.makeText(context, "发生未知错误", Toast.LENGTH_SHORT).show() return false } } }
3.2 获取经纬度信息
在申请到权限后,进行如下操作来获取经纬度信息
- 判断是否开启位置服务,没有则跳转至系统设置打开定位服务
判断定位服务有没有开启主要通过以下方法
讯享网
var gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)当返回true,代表GPS定位服务开启,NETWORK_PROVIDER同理
- 获取所有支持的provider,然后通过provider来获取定位信息
- 当返回true,代表GPS定位服务开启,NETWORK_PROVIDER同理
- 若所支持的provider获取到的经纬度均为空,则开启连续定位监听
完整代码如下:
fun getLocationInfo() {
//判断是否开启位置服务,没有则跳转至设置来开启 if (isLocationServiceOpen()) {
//获取所有支持的provider val providers = locationManager.getProviders(true) //用来存储最优的结果 var betterLocation: Location? = null for (provider in providers) {
val location = locationManager.getLastKnownLocation(provider) location?.let {
Log.i(TAG, "$provider 精度为:${
it.accuracy}") if (betterLocation == null) {
betterLocation = it } else {
//因为半径等于精度,所以精度越低代表越准确 if (it.accuracy < betterLocation!!.accuracy) betterLocation = it } } if (location == null) {
Log.i(TAG, "$provider 获取到的位置为null") } } betterLocation?.let {
Log.i(TAG, "精度最高的获取方式:${
it.provider} 经度:${
it.longitude} 纬度:${
it.latitude}") } //(四)若所支持的provider获取到的位置均为空,则开启连续定位服务 if (betterLocation == null) {
for (provider in locationManager.getProviders(true)) {
locationMonitor(provider) } Log.i(TAG, "getLocationInfo: 获取到的经纬度均为空,已开启连续定位监听") } } else {
Toast.makeText(this, "请跳转到系统设置中打开定位服务", Toast.LENGTH_SHORT).show() } } / * 判断定位服务是否开启 */ private fun isLocationServiceOpen(): Boolean {
var gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) var network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) //有一个开启就可 return gps || network }
3.2 开启连续监听
在1.4中我们已经讲了LocationListener,如何开启连续监听,这里就不再详细讲述
具体代码如下
讯享网fun locationMonitor(provider: String) {
if (PermissionUtil.requestPermission( LISTENER_REQUEST_CODE, permissionList.toList(), this ) ) {
locationManager.requestLocationUpdates( provider, 60000.toLong(), //超过1分钟则更新位置信息 8.toFloat(), //位置超过8米则更新位置信息 locationListener ) } }
4. 总结
以上就是安卓原生获取经纬度信息的全部内容,如果通过以上方法都获取不到的话,那就使用高德或百度等第三方SDK吧。
如果本文对你有帮助,请别忘记点赞start,如果有不恰当的地方也请提出来,下篇文章见。
关注公众号,回复 原生经纬度 获取文章源码

项目地址
5. 参考文章
10.14 Android GPS初涉 | 菜鸟教程 (runoob.com)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/38436.html