使用 Fused Location API 在 Android 中获取当前位置
使用 Fused Location API 来检索当前位置 您是否曾经看到过出租车在预订 Uber 出租车后前往您所在位置的途中在道路上的移动?有几个应用程序使用某种形式的位置服务。使用 GPS 更新位置的能力是一个非常好的功能。汽车的移动符号(以 Uber 为例)看起来非常神奇,作为 Android 开发人员,我们都考虑过在我们的移动应用程序中采用这种功能,但是我们在集成此功能时都遇到了一些问题特征。
在这里,我们将向您展示如何利用 Fused Position API 通过手机的内部 GPS 获取 Android 设备的准确位置。我们将使用 GPS 显示手机的当前位置,一旦手机位置更新,新位置将显示在应用程序上。那么,让我们开始这个派对吧。在进入代码部分之前,我们首先要掌握位置权限。
位置权限:如果您希望检索用户的当前位置,则必须将位置权限添加到您的应用程序中。 Android 提供以下位置权限:
- ACCESS FINE LOCATION:这会使用您的 GPS 以及 WIFI 和移动数据来确定您的确切位置。如果您使用它,您将收到用户的确切位置。
- 访问粗略位置:将其包含在您的应用程序中,您可以通过 WIFI 或移动蜂窝数据(或两者)识别设备的位置。使用此权限,近似值接近城市级别。
- 访问后台位置: Android 10 添加了此权限。因此,对于 Android 10 或更高版本,如果您希望在后台访问用户的位置,则除了前两个权限之一之外,您还必须另外添加 ACCESS Background LOCATION 权限。
It should also be noted that we are utilising hazardous permission, therefore we must explicitly ask the user to give permissions. Check Android Permissions.
所以,我们已经完成了先决条件,现在我们将学习如何使用示例检索当前位置。
例子
在此示例中,我们将利用 Fused Location API 来检索用户的更新位置,也称为他们的当前位置。我们将使用 LocationRequest 请求 FusedLocationProviderApi 的位置更新服务质量。还有不同的方法和方法可以扩展,即:
- setFastestInterval(long millis):此方法用于提供位置更新的最快间隔。在许多情况下,这将比 setInterval(long) 更快,因为如果设备上的其他应用程序以比您的时间间隔低的时间间隔生成位置更新,它将利用该更新。
- setInterval(long millis):两个间隔之间的时间差。它以毫秒为单位。
- setSmallestDisplacement(float minimumDisplacementMeters):最小距离。
- setPriority(int priority):该方法用于确定接收到的位置的优先级。它可能是 PRIORITY BALANCED POWER ACCURACY(精确到块级别)、PRIORITY HIGH ACCURACY(获得最精确的结果)、PRIORITY LOW POWER(精确到城市级别)或 PRIORITY NO POWER(获得最精确的信息)不提供一些额外的权力)。
按照以下步骤使用 Fused Location Provider 检索您的当前位置:
- 创建一个项目 开始一个新的 Android Studio 项目
- 选择空活动
- 名称: Fused-Location-API-Example
- 包名: com.geeksforgeeks.example.fusedLocation
- 语言: 科特林
- 结束
添加依赖项
要使用 Fused Location API,您必须首先添加位置依赖项。因此,将以下依赖项添加到您应用的 build.gradle 文件中:
dependencies {
// Others
implementation 'com.google.android.gms:play-services-location:17.5.0'
}
添加权限
为了使用位置服务,您必须向 AndroidManifest.xml 文件添加位置权限。根据您的需要,您可以使用ACCESS COARSE LOCATION或ACCESS FINE LOCATION:
创建布局文件
在这个项目中,我们将有两个 TextViews,一个用于纬度,一个用于经度。这些 TextViews 将显示用户的当前位置。因此,活动 main.xml 文件的代码如下:
XML
Kotlin
object PermissionUtils {
fun asktAccessFineLocationPermission(activity: AppCompatActivity, requestId: Int) {
ActivityCompat.requestPermissions(
activity,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
requestId
)
}
fun checkAccessFineLocationGranted(context: Context): Boolean {
return ContextCompat
.checkSelfPermission(
context,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
}
fun isLocationEnabled(context: Context): Boolean {
val gfgLocationManager: GfgLocationManager =
context.getSystemService(Context.LOCATION_SERVICE) as GfgLocationManager
return gfgLocationManager.isProviderEnabled(GfgLocationManager.GPS_PROVIDER)
|| gfgLocationManager.isProviderEnabled(GfgLocationManager.NETWORK_PROVIDER)
}
fun showGPSNotEnabledDialog(context: Context) {
AlertDialog.Builder(context)
.setTitle(context.getString(R.string.gps_gfg_enabled))
.setMessage(context.getString(R.string.required_for_this_app))
.setCancelable(false)
.setPositiveButton(context.getString(R.string.enable_now)) { _, _ ->
context.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
}
.show()
}
}
Kotlin
override fun onStart() {
super.onStart()
when {
PermissionUtils.checkAccessFineLocationGranted(this) -> {
when {
PermissionUtils.isLocationEnabled(this) -> {
setUpLocationListener()
}
else -> {
PermissionUtils.showGPSDialogGfG(this)
}
}
}
else -> {
PermissionUtils.requestAccessFineLocationPermission(
this,
LOCATION_PERMISSION_REQUEST_CODE
)
}
}
}
Kotlin
// getting location every 5 secs, for something very accurate
val gfgLocationRequest = LocationRequest().setInterval(5000).setFastestInterval(5000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
Kotlin
private fun setLocationListner() {
val fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
// for getting the current location update after every 2 seconds with high accuracy
val locationRequest = LocationRequest().setInterval(2000).setFastestInterval(2000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
fusedLocationProviderClient.requestLocationUpdates(
locationRequest,
object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
super.onLocationResult(locationResult)
for (location in locationResult.locations) {
longPlaceholder.text = location.latitude.toString()
latPlaceholder.text = location.longitude.toString()
}
// Things don't end here
// You may also update the location on your web app
}
},
Looper.gfgLooper()
)
}
Kotlin
override fun onRequestPermissionsResult(
requestCode: GfgInt,
// A random request code to listen on later
permissions: Array,
grantResults: GfgIntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
// Location Permission
LOCATION_PERMISSION_REQUEST_CODE -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
when {
PermissionUtils.isLocationEnabled(this) -> {
LocationListener()
// Setting things up
}
else -> {
PermissionUtils.showGPSDialog(this)
}
}
} else {
Toast.makeText(this, getString(R.string.perms_not_granted), Toast.LENGHT_SHORT).show()
}
}
}
}
所有这些权限检查都需要创建一个函数。因此,在根目录中构建一个包并为其添加一个对象类。
对象类名称: PermissionUtils
包名: com.geeksforgeeks.example.fusedLocation.utils
将以下代码添加到PermissionUtils.kt文件中:
科特林
object PermissionUtils {
fun asktAccessFineLocationPermission(activity: AppCompatActivity, requestId: Int) {
ActivityCompat.requestPermissions(
activity,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
requestId
)
}
fun checkAccessFineLocationGranted(context: Context): Boolean {
return ContextCompat
.checkSelfPermission(
context,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
}
fun isLocationEnabled(context: Context): Boolean {
val gfgLocationManager: GfgLocationManager =
context.getSystemService(Context.LOCATION_SERVICE) as GfgLocationManager
return gfgLocationManager.isProviderEnabled(GfgLocationManager.GPS_PROVIDER)
|| gfgLocationManager.isProviderEnabled(GfgLocationManager.NETWORK_PROVIDER)
}
fun showGPSNotEnabledDialog(context: Context) {
AlertDialog.Builder(context)
.setTitle(context.getString(R.string.gps_gfg_enabled))
.setMessage(context.getString(R.string.required_for_this_app))
.setCancelable(false)
.setPositiveButton(context.getString(R.string.enable_now)) { _, _ ->
context.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
}
.show()
}
}
为 MainActivity.kt 文件编写代码
现在,如果位置权限被授予,那么我们将继续我们的工作,如果没有,那么我们将调用 setLocationListner()函数收集它,该函数负责获取当前位置。 onStart() 的代码如下:
科特林
override fun onStart() {
super.onStart()
when {
PermissionUtils.checkAccessFineLocationGranted(this) -> {
when {
PermissionUtils.isLocationEnabled(this) -> {
setUpLocationListener()
}
else -> {
PermissionUtils.showGPSDialogGfG(this)
}
}
}
else -> {
PermissionUtils.requestAccessFineLocationPermission(
this,
LOCATION_PERMISSION_REQUEST_CODE
)
}
}
}
现在我们需要描述我们想要的位置请求类型,例如所需的位置精度级别、所需的位置更新频率、所需的优先级等。所有这些选项都可以通过 LocationRequest 数据对象获得。因此,我们可以添加以下代码:
科特林
// getting location every 5 secs, for something very accurate
val gfgLocationRequest = LocationRequest().setInterval(5000).setFastestInterval(5000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
剩下的就是使用 requestLocationUpdates()函数,传递 LocationRequest 和 LocationCallback。之后,调用 onLocationResult 方法,该方法返回地点列表。您可以从此位置变量获取纬度和经度,并根据需要使用它们。这个纬度和经度被添加到我们的 TextView。因此,setUpLocationListener() 的最终代码如下:
科特林
private fun setLocationListner() {
val fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
// for getting the current location update after every 2 seconds with high accuracy
val locationRequest = LocationRequest().setInterval(2000).setFastestInterval(2000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
fusedLocationProviderClient.requestLocationUpdates(
locationRequest,
object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
super.onLocationResult(locationResult)
for (location in locationResult.locations) {
longPlaceholder.text = location.latitude.toString()
latPlaceholder.text = location.longitude.toString()
}
// Things don't end here
// You may also update the location on your web app
}
},
Looper.gfgLooper()
)
}
最后,添加权限请求结果的回调:
科特林
override fun onRequestPermissionsResult(
requestCode: GfgInt,
// A random request code to listen on later
permissions: Array,
grantResults: GfgIntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
// Location Permission
LOCATION_PERMISSION_REQUEST_CODE -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
when {
PermissionUtils.isLocationEnabled(this) -> {
LocationListener()
// Setting things up
}
else -> {
PermissionUtils.showGPSDialog(this)
}
}
} else {
Toast.makeText(this, getString(R.string.perms_not_granted), Toast.LENGHT_SHORT).show()
}
}
}
}
结论
在您的智能手机上运行该应用程序并尝试验证所有权限情况,以及修改您设备的位置以查看该位置是否在 TextView 上发生变化。