Android原生获取经纬度位置信息

前言

因为项目中经常会遇到要上传一系列设备信息的功能,为了方便使用,所以就拆分成以下系列文章来单独介绍如何获取各类设备信息

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)

  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
Android 应用中,你可以使用 Google Maps Android API 来根据经纬度获取地址。下面是一个简单的示例,你可以在你的项目中使用它: 1. 首先,在你的项目的 `build.gradle` 文件中添加以下依赖: ```gradle implementation 'com.google.android.gms:play-services-maps:17.0.1' ``` 2. 在你的布局文件中添加一个 MapView 元素: ```xml <com.google.android.gms.maps.MapView android:id="@+id/map_view" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 3. 在你的 Activity 或 Fragment 中,初始化 MapView 并获取 GoogleMap 实例: ```java import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.MapView; import com.google.android.gms.maps.OnMapReadyCallback; public class MainActivity extends AppCompatActivity implements OnMapReadyCallback { private MapView mapView; private GoogleMap googleMap; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mapView = findViewById(R.id.map_view); mapView.onCreate(savedInstanceState); mapView.getMapAsync(this); } @Override public void onMapReady(GoogleMap map) { googleMap = map; // 在此处添加你的逻辑代码 } } ``` 4. 在 `onMapReady` 方法中,可以使用 `Geocoder` 类来根据经纬度获取地址: ```java import android.location.Address; import android.location.Geocoder; @Override public void onMapReady(GoogleMap map) { googleMap = map; double latitude = 40.712776; double longitude = -74.005974; Geocoder geocoder = new Geocoder(this); try { List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1); if (addresses.size() > 0) { Address address = addresses.get(0); String formattedAddress = address.getAddressLine(0); // 在此处处理获取到的地址 } } catch (IOException e) { e.printStackTrace(); } } ``` 在上述代码中,你可以将 `latitude` 和 `longitude` 替换为你要查询的经纬度。然后,通过创建 `Geocoder` 对象并调用 `getFromLocation` 方法来获取地址。如果成功获取到地址,你可以在 `formattedAddress` 变量中获取到格式化的地址字符串。 请确保你已在 AndroidManifest.xml 文件中添加了适当的权限和 API 密钥。 希望这对你有所帮助!如果有任何其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

重拾丢却的梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值