使用Android 原生LocationManager获取经纬度

一、常用方案

1、使用LocationManager GPS和网络定位

**缺点:**个别设备,室内或者地下停车场获取不到gps定位,故需要和网络定位相结合使用

2、使用Google Play服务

这种方案需要Android手机中有安装谷歌服务,然后导入谷歌的第三方库:

例如:implementation 'com.google.android.gms:play-services-location:20.0.0'

**缺点:**一些厂商可能会阉割掉谷歌服务

3、使用第三方地图定位

**缺点:**该方法准确度较高,但需要在第三方平台注册账号和集成key

这里介绍第一种方案,如果获取不到gps,先通过网络定位获取,然后再尝试去获取gps

博主这里就遇到同一个地方,小米可以通过gps获取到数据,但一加的两个手机,都无法通过gps获取到经纬度,故只能先从网络获取经纬度

二、方案实现

Kotlin 复制代码
class LocationManagerUtil {

    val TAG: String = "LocationManagerUtil_"
    var mLocationManager:LocationManager?=null
    var mLocationListener:LocationListener?=null
    var isSendLocation=true

    companion object {
        private var singleInstance: LocationManagerUtil? = null
            get() {
                // 懒汉模式
                if (null == field) {
                    field = LocationManagerUtil()
                }
                return field
            }

        @Synchronized // 添加注解,线程同步,线程安全
        fun getInstance(): LocationManagerUtil {
            return singleInstance!!
        }
    }



     fun registerListener(callback: LocationCallback){
         isSendLocation=true
         unRegisterListener()

         mLocationManager = WebrtcSdkApplication.instance.getSystemService(Context.LOCATION_SERVICE) as LocationManager?

         mLocationListener = object : LocationListener {
             override fun onLocationChanged(location: Location) {
                 if(location!=null){
                     // 当位置发生变化时调用
                     val latitude = location.latitude
                     val longitude = location.longitude
                     val provider=location.provider
                     // 使用位置信息
                     XLogUtil.d("${TAG}onLocationChanged longitude:$longitude,,,latitude:$latitude")

                     //在室内或者地下室,gps可能会获取不到地位,这时先根据网络定位,待获取到gps值后,关闭监听
                     if(provider==LocationManager.GPS_PROVIDER){
                         isSendLocation=false
                         unRegisterListener()
                         callback.onLocationChanged(longitude,latitude)
                     }else if(provider==LocationManager.NETWORK_PROVIDER){
                         if(isSendLocation){
                             callback.onLocationChanged(longitude,latitude)
                         }
                         isSendLocation=false
                     }

                 }else{
                     XLogUtil.d("${TAG}onLocationChanged location==null")
                 }
             }

             override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {
                 // 当GPS状态改变时调用
             }

             override fun onProviderEnabled(provider: String) {
                 // 当选中的位置提供者被激活时调用
             }

             override fun onProviderDisabled(provider: String) {
                 // 当选中的位置提供者被停用时调用
             }
         }

         if (ActivityCompat.checkSelfPermission(
                 WebrtcSdkApplication.instance,
                 Manifest.permission.ACCESS_FINE_LOCATION
             ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
                 WebrtcSdkApplication.instance,
                 Manifest.permission.ACCESS_COARSE_LOCATION
             ) != PackageManager.PERMISSION_GRANTED
         ) {
            //Toast.makeText(WebrtcSdkApplication.instance,WebrtcSdkApplication.instance.getString(R.string.please_enable_location_permissions_in_settings),Toast.LENGTH_SHORT).show()

             XLogUtil.d("${TAG}checkSelfPermission 定位权限未授权")
         }

         mLocationManager?.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L, 5f,
             mLocationListener!!
         )//更新间隔1000毫秒,距离间隔5米

         mLocationManager?.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000L, 5f,
             mLocationListener!!
         )//更新间隔1000毫秒,距离间隔5米
    }

    fun unRegisterListener(){
        if(mLocationListener!=null){
            mLocationManager?.removeUpdates(mLocationListener!!)
            mLocationManager=null
            mLocationListener=null
        }
    }

}

三、相关权限

Kotlin 复制代码
  <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" 
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" 
    <uses-permission android:name="android.permission.INTERNET" />

    <!--定位权限-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
   <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/>



 //以下两个权限需要动态申请权限
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

四、判断是否打开了gps

Kotlin 复制代码
    val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
        if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            // 提示用户开启GPS
            val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
            startActivity(intent)
        }

五、获取的经纬度在不同地图上显示不一致问题解答

GPS获得的经纬度所用的坐标系和谷歌地图、百度地图上的坐标系是不同的,GPS硬件获得的经纬度是WGS-84标准,国际通用,

可以看成是正常的GPS位置,在google earth上全部坐标,谷歌地图上除中国以外的坐标均为这个标准,但是谷歌地图的中国坐标使用的是GCJ-02标准,

是天朝测绘局在WGS-84的基础上加入随机偏差加密后的一种经纬度,会随机偏移一公里左右,所以导致无论怎样定位总是显示不对。

而百度地图在GCJ-02上又加入了自己的加密算法,变成了BD-09标准,另外其他很多的地图都有自己的加密方法。

这些都是硬件获取经纬度在地图上指示不对的原因,网上有免费做转换的网站,

在这里推荐一个:http://map.yanue.NET/gps.html,如果发现GPS定位结果总是有误差,可以用这个转换一下

经纬度转换为地点:【经纬度查询】在线地图经度纬度查询|经纬度地名坐标转换

相关推荐
Propeller1 天前
【Android】动态操作 Window 的背后机制
android·java
张风捷特烈1 天前
Flutter&TolyUI#12 | 树形组件 toly_tree 重磅推出!
android·前端·flutter
柯南二号1 天前
【大前端】【Android】一文详解Android MVVM 模式详情解析
android·前端
feathered-feathered1 天前
Redis【事务】(面试相关)与MySQL相比较,重点在Redis事务
android·java·redis·后端·mysql·中间件·面试
Kapaseker1 天前
三分钟搞懂 Kotlin Flow 中的背压
android·kotlin
柯南二号1 天前
【大前端】【Android】把 Activity 重构成 MVVM 的对比示例
android·状态模式
某空m1 天前
【Android】Glide的缓存机制
android·缓存·glide
某空m1 天前
【Android】Glide的使用
android·glide
QING6181 天前
Jetpack Compose 中的 ViewModel 作用域管理 —— 新手指南
android·kotlin·android jetpack
鹏多多1 天前
flutter-使用EventBus实现组件间数据通信
android·前端·flutter