📌  相关文章
📜  如何在 Android 中获取当前位置?

📅  最后修改于: 2022-05-13 01:55:05.402000             🧑  作者: Mango

如何在 Android 中获取当前位置?

作为一名开发人员,当您在 Android 中处理位置时,您总是对选择最适合您需求的最佳和有效方法有一些疑问。所以在本文中,我们将讨论如何在 Android 中获取用户的当前位置。有两种方法可以获取任何 Android 设备的当前位置:

  1. Android 的位置管理器 API
  2. 融合位置提供者:Google Play 服务位置 API

在移动上述任何方法之前,我们必须获得位置许可。

取得位置许可

步骤 1:在清单文件中定义用于位置访问的使用权限



第 2 步:定义使用互联网访问权限,因为我们将使用互联网提供商。

第 3 步:编写一个函数来检查位置权限是否被授予。如果未授予权限,则在运行时请求权限。

Kotlin
private fun isLocationPermissionGranted(): Boolean {
    return if (ActivityCompat.checkSelfPermission(
            this,
            android.Manifest.permission.ACCESS_COARSE_LOCATION
        ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
            this,
            android.Manifest.permission.ACCESS_FINE_LOCATION
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        ActivityCompat.requestPermissions(
            this,
            arrayOf(
                android.Manifest.permission.ACCESS_FINE_LOCATION,
                android.Manifest.permission.ACCESS_COARSE_LOCATION
            ),
            requestcode
        )
        false
    } else {
        true
    }
}


Kotlin
private var currentLocation: Location? = null
lateinit var locationManager: LocationManager
locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager


Kotlin
val hasGps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
//------------------------------------------------------//
val hasNetwork = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)


Kotlin
val gpsLocationListener: LocationListener = object : LocationListener {
    override fun onLocationChanged(location: Location) {
        locationByGps= location
    }
  
    override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
    override fun onProviderEnabled(provider: String) {}
    override fun onProviderDisabled(provider: String) {}
}
//------------------------------------------------------//
val networkLocationListener: LocationListener = object : LocationListener {
    override fun onLocationChanged(location: Location) {
        locationByNetwork= location
    }
  
    override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
    override fun onProviderEnabled(provider: String) {}
    override fun onProviderDisabled(provider: String) {}
}


Kotlin
if (hasGps) {
    locationManager.requestLocationUpdates(
        LocationManager.GPS_PROVIDER,
        5000,
        0F,
        gpsLocationListener
    )
}
//------------------------------------------------------//
if (hasNetwork) {
    locationManager.requestLocationUpdates(
        LocationManager.NETWORK_PROVIDER,
        5000,
        0F,
        networkLocationListener
    )
}


Kotlin
val lastKnownLocationByGps =
  locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
lastKnownLocationByGps?.let {
    locationByGps = lastKnownLocationByGps
}
//------------------------------------------------------//
val lastKnownLocationByNetwork =
  locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
lastKnownLocationByNetwork?.let {
    locationByNetwork = lastKnownLocationByNetwork
}
//------------------------------------------------------//
if (locationByGps != null && locationByNetwork != null) {
    if (locationByGps.accuracy > locationByNetwork!!.accuracy) {
        currentLocation = locationByGps
        latitude = currentLocation.latitude
        longitude = currentLocation.longitude
        // use latitude and longitude as per your need
    } else {
        currentLocation = locationByNetwork
        latitude = currentLocation.latitude
        longitude = currentLocation.longitude
        // use latitude and longitude as per your need
    }
}


Kotlin
// FusedLocationProviderClient - Main class for receiving location updates.
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
  
// LocationRequest - Requirements for the location updates, i.e.,
// how often you should receive updates, the priority, etc.
private lateinit var locationRequest: LocationRequest
  
// LocationCallback - Called when FusedLocationProviderClient
// has a new Location
private lateinit var locationCallback: LocationCallback
  
// This will store current location info
private var currentLocation: Location? = null


Kotlin
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)


Kotlin
locationRequest = LocationRequest().apply {
    // Sets the desired interval for
      // active location updates. 
      // This interval is inexact.
    interval = TimeUnit.SECONDS.toMillis(60)
  
    // Sets the fastest rate for active location updates. 
     // This interval is exact, and your application will never
      // receive updates more frequently than this value
    fastestInterval = TimeUnit.SECONDS.toMillis(30)
  
    // Sets the maximum time when batched location 
      // updates are delivered. Updates may be
      // delivered sooner than this interval
    maxWaitTime = TimeUnit.MINUTES.toMillis(2)
  
    priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}


Kotlin
locationCallback = object : LocationCallback() {
    override fun onLocationResult(locationResult: LocationResult?) {
        super.onLocationResult(locationResult)
        locationResult?.lastLocation?.let {
            currentLocation = locationByGps
            latitude = currentLocation.latitude
            longitude = currentLocation.longitude
            // use latitude and longitude as per your need
        } ?: {
            Log.d(TAG, "Location information isn't available.")
        }
    }
}


Kotlin
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper())


Kotlin
val removeTask = fusedLocationProviderClient.removeLocationUpdates(locationCallback)
removeTask.addOnCompleteListener { task ->
   if (task.isSuccessful) {
       Log.d(TAG, "Location Callback removed.")
   } else {
       Log.d(TAG, "Failed to remove Location Callback.")
   }
}


现在处理位置权限后,我们将学习如何在android中获取位置。

第一种方法:通过 Android 的位置管理器 API

我们假设用户已被授予位置权限。如果没有,请先询问。

步骤 1:在 LOCATION_SERVICE 的上下文中创建 LocationManager 的实例。

科特林

private var currentLocation: Location? = null
lateinit var locationManager: LocationManager
locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager

第 2 步:检查 GPS 和网络是否可用,如果两者都可用,那么我们使用更准确的一个。

科特林

val hasGps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
//------------------------------------------------------//
val hasNetwork = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)

第 3 步:为(GPS 和网络)创建一个 LocationListener 实例(包:android.location)。



科特林

val gpsLocationListener: LocationListener = object : LocationListener {
    override fun onLocationChanged(location: Location) {
        locationByGps= location
    }
  
    override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
    override fun onProviderEnabled(provider: String) {}
    override fun onProviderDisabled(provider: String) {}
}
//------------------------------------------------------//
val networkLocationListener: LocationListener = object : LocationListener {
    override fun onLocationChanged(location: Location) {
        locationByNetwork= location
    }
  
    override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
    override fun onProviderEnabled(provider: String) {}
    override fun onProviderDisabled(provider: String) {}
}

第 4 步:如果启用了任何 GPS 或网络提供商,那么我们将使用 LocationListener 从 LocationManager 请求当前位置更新。

科特林

if (hasGps) {
    locationManager.requestLocationUpdates(
        LocationManager.GPS_PROVIDER,
        5000,
        0F,
        gpsLocationListener
    )
}
//------------------------------------------------------//
if (hasNetwork) {
    locationManager.requestLocationUpdates(
        LocationManager.NETWORK_PROVIDER,
        5000,
        0F,
        networkLocationListener
    )
}

第 5 步:现在我们检查哪个提供商为我们提供了更准确的位置,然后我们将根据我们的要求使用该位置。

科特林

val lastKnownLocationByGps =
  locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
lastKnownLocationByGps?.let {
    locationByGps = lastKnownLocationByGps
}
//------------------------------------------------------//
val lastKnownLocationByNetwork =
  locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
lastKnownLocationByNetwork?.let {
    locationByNetwork = lastKnownLocationByNetwork
}
//------------------------------------------------------//
if (locationByGps != null && locationByNetwork != null) {
    if (locationByGps.accuracy > locationByNetwork!!.accuracy) {
        currentLocation = locationByGps
        latitude = currentLocation.latitude
        longitude = currentLocation.longitude
        // use latitude and longitude as per your need
    } else {
        currentLocation = locationByNetwork
        latitude = currentLocation.latitude
        longitude = currentLocation.longitude
        // use latitude and longitude as per your need
    }
}

现在,在了解了如何通过 Location Manager API 获取 android 中的位置后,我们将转向第二种方法Fused Location Provider (Google Play Services Location APIs)

第二种方法:通过融合位置提供者

我们假设用户已被授予位置权限。如果没有,请先询问。 Fused Location Provider 是 Google Play 服务的位置 API。它提供了一个简单的 API,用于获取高、中和低精度的位置。它还优化了设备对电池电量的使用。所以我们应该更喜欢这种方法。

第一步:声明FusedLocationProviderClient、LocationRequest、LocationCallback、Location的变量。

科特林

// FusedLocationProviderClient - Main class for receiving location updates.
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
  
// LocationRequest - Requirements for the location updates, i.e.,
// how often you should receive updates, the priority, etc.
private lateinit var locationRequest: LocationRequest
  
// LocationCallback - Called when FusedLocationProviderClient
// has a new Location
private lateinit var locationCallback: LocationCallback
  
// This will store current location info
private var currentLocation: Location? = null

第二步:初始化 fusedLocationProviderClient。



科特林

fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)

第三步:初始化locationRequest。

科特林

locationRequest = LocationRequest().apply {
    // Sets the desired interval for
      // active location updates. 
      // This interval is inexact.
    interval = TimeUnit.SECONDS.toMillis(60)
  
    // Sets the fastest rate for active location updates. 
     // This interval is exact, and your application will never
      // receive updates more frequently than this value
    fastestInterval = TimeUnit.SECONDS.toMillis(30)
  
    // Sets the maximum time when batched location 
      // updates are delivered. Updates may be
      // delivered sooner than this interval
    maxWaitTime = TimeUnit.MINUTES.toMillis(2)
  
    priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}

第四步:初始化locationCallback。

科特林

locationCallback = object : LocationCallback() {
    override fun onLocationResult(locationResult: LocationResult?) {
        super.onLocationResult(locationResult)
        locationResult?.lastLocation?.let {
            currentLocation = locationByGps
            latitude = currentLocation.latitude
            longitude = currentLocation.longitude
            // use latitude and longitude as per your need
        } ?: {
            Log.d(TAG, "Location information isn't available.")
        }
    }
}

第 5 步:既然您已经初始化了所有内容,您需要让 FusedLocationProviderClient 知道您想要接收更新。所以订阅位置变化。

科特林

fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper())

第 6 步:当应用不再需要访问位置信息时,取消订阅位置更新非常重要。

科特林

val removeTask = fusedLocationProviderClient.removeLocationUpdates(locationCallback)
removeTask.addOnCompleteListener { task ->
   if (task.isSuccessful) {
       Log.d(TAG, "Location Callback removed.")
   } else {
       Log.d(TAG, "Failed to remove Location Callback.")
   }
}

现在还有一点要支持 Android 10 和 Android R。那么让我们来谈谈吧……



支持安卓 10

步骤 1:在 build.gradle 文件中进行这些更改。

  1. 将 compileSdkVersion 设置为 29。
  2. 将 buildToolsVersion 设置为“29.0.3”。
  3. 将 targetSdkVersion 设置为 29。

您的代码应如下所示:

第 2 步:如果您有前台服务,请在清单中声明位置的 foregroundServiceType。

您的代码应如下所示:

支持 Android 11 或 Android R

好消息,除了 build.gradle 文件之外,您不需要更改任何文件!进行这些更改:

  1. compileSdkVersion 为“android-R”
  2. targetSdkVersion 到“R”

您的代码应如下所示:

想要一个更快节奏和更具竞争力的环境来学习 Android 的基础知识吗?
单击此处前往由我们的专家精心策划的指南,旨在让您立即做好行业准备!