GetFusedLocationProviderClient 返回用户位置的空纬度和经度值

GetFusedLocationProviderClient returning null latitude and longitude values for users' location

对于我正在制作的应用程序,我需要获取用户的位置,然后将其显示在地图上。

为此,我在下面的代码中使用了 LocationServices.getFusedLocationProviderClient()。

当我在 addOnSuccessListener 中获取位置值时,纬度和经度值由于某种原因为空,因此我收到 NullPointerException:

import android.Manifest
import android.annotation.SuppressLint
import android.location.Location
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.core.app.ActivityCompat
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.realtomjoney.mapsapp.databinding.ActivityMainBinding
import java.lang.NullPointerException

class MainActivity : AppCompatActivity(), OnMapReadyCallback {
    private lateinit var binding: ActivityMainBinding

    lateinit var myMap: GoogleMap

    lateinit var fusedLocation: FusedLocationProviderClient

    @SuppressLint("MissingPermission")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        ActivityCompat.requestPermissions(this, arrayOf(
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION) , 100)

        val mapFragment = supportFragmentManager
            .findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync(this)

        binding.button2.setOnClickListener {
            fusedLocation = LocationServices.getFusedLocationProviderClient(this)
            fusedLocation.lastLocation.addOnSuccessListener { location: Location? ->
                val latLong = LatLng(location!!.latitude, location.longitude)
                myMap.addMarker(MarkerOptions().position(latLong).title("Found Location"))

                myMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLong, 10f))
            }
        }
    }

    override fun onMapReady(p0: GoogleMap) {
        myMap = p0
    }

}

当我 运行 应用程序时,出现以下异常:

2021-10-19 16:46:09.859 8556-8556/com.realtomjoney.mapsapp E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.realtomjoney.mapsapp, PID: 8556
    java.lang.NullPointerException
        at com.realtomjoney.mapsapp.MainActivity.onCreate$lambda-1$lambda-0(MainActivity.kt:46)
        at com.realtomjoney.mapsapp.MainActivity.$r8$lambda$wwcxhtPyugLtHLn65vCEt3JY33Q(Unknown Source:0)
        at com.realtomjoney.mapsapp.MainActivity$$ExternalSyntheticLambda1.onSuccess(Unknown Source:4)
        at com.google.android.gms.tasks.zzn.run(com.google.android.gms:play-services-tasks@@17.2.0:4)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7842)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)

是的,我在第一次 运行 应用程序时同意了所有权限。

如果这个问题写得不好或重复,请告诉我,因为我会努力创建结构良好的好问题。

出于多种原因,lastLocation 可能为空。 它们列在这里 https://developer.android.com/training/location/retrieve-current#last-known

首先,初始化用户坐标到地图时不为空的正确步骤是在 onConnected() 回调上初始化地图,而不是 activity 或片段中的 onCreate() , lastLocation 可以是空。

如果不使用location observer,您可以使用REQUEST_CODE_ASK_PERMISSIONS来处理回调,位置观察器基本上看起来像这样

if (location.provider == LocationManager.GPS_PROVIDER) {
                getData()
            }

我以前遇到过同样的情况,我的代码在权限回调上是这样的:

if (isGranted()) {
            try {
                fusedLocationProviderClient.lastLocation.addOnCompleteListener {
                    if (it.isSuccessful) {
                        if (it.result != null) {
                            setLocationData(it.result)
                        }
                    }
                }
            } catch (e: Exception) {
            }

基本上在获得许可的情况下,它会获取您的位置,您可以选择是否要将其用于添加标记或其他任何内容。

我也遇到过这个问题,尤其是当我第一次在设备上安装我的应用程序时。有两件事你可以尝试,我认为会有帮助:

一个人正在尝试打开 google 地图应用程序并等待它获得修复,然后继续并打开您的应用程序。这应该为您的融合位置提供者客户端提供它可以查找的最后一个位置。检查此 以供参考

第二个是更进一步,使用提供商请求 location updates。如果您只需要一个位置修复,您可以在获得第一个位置后继续并注销它。我正在为我的应用程序执行此操作,通常最后一个位置在我安装后第一次使用该应用程序时仅为空。之后它通常会起作用。这可能是您无论如何都应该做的,因为您不能期望您的用户在使用您的应用程序之前打开 google 地图。

为了安全起见,请注意当您的设备上有待处理的 google 服务更新时,fusedlocationproviderclient 有时会停止工作或行为异常。因此,请继续并确保您的设备在这方面是最新的。

我遇到了同样的问题

  1. 检查设备上的GPS是否开启
  2. 可能是因为您正在使用的 google 地图 api 密钥的计费 有时检查所有这些错误日志显示 google 地图计费问题

看起来您请求了权限(ActivityCompat.requestPermissions(...))但从未处理过权限请求(您需要覆盖 onRequestPermissionsResult(...))。更多信息:https://developer.android.com/training/permissions/requesting#manage-request-code-yourself

或者您可以切换到新方法让系统管理请求代码:https://developer.android.com/training/permissions/requesting#allow-system-manage-request-code

最后一件事,在某些情况下 getLastLocation() 可以 return 为空,在这种情况下我调用 getCurrentLocation() 总是 return 新的设备位置,更多信息在这里:https://developer.android.com/training/location/retrieve-current#BestEstimate