You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用GetFusedLocationProviderClient获取用户位置时经纬度返回空值引发NullPointerException问题排查

Fixing the NullPointerException in FusedLocationProviderClient

Hey there, let's break down why you're hitting that NullPointerException and walk through how to fix it properly. The crash happens because you're using location!! to force a non-null value, but lastLocation is returning null—and there are a few common reasons for that:

  • Your device's location services might be turned off
  • The device has never recorded a location before (like a new device or after a reset)
  • The cached location data was cleared by the system
  • You're trying to access location before the user actually grants the requested permissions

Let's go through the fixes one by one:

1. Fix Permission Handling First

Right now, you request permissions in onCreate, but if the user taps the button before allowing permissions, you'll still try to fetch location without proper access. Let's add a check to ensure permissions are granted before proceeding:

binding.button2.setOnClickListener {
    // Check if permissions are granted first
    val hasFineLocation = ActivityCompat.checkSelfPermission(
        this,
        Manifest.permission.ACCESS_FINE_LOCATION
    ) == PackageManager.PERMISSION_GRANTED
    val hasCoarseLocation = ActivityCompat.checkSelfPermission(
        this,
        Manifest.permission.ACCESS_COARSE_LOCATION
    ) == PackageManager.PERMISSION_GRANTED

    if (!hasFineLocation && !hasCoarseLocation) {
        // Re-request permissions if they're missing
        ActivityCompat.requestPermissions(
            this,
            arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION),
            100
        )
        return@setOnClickListener
    }

    // Proceed with location fetch only if permissions are granted
    fusedLocation = LocationServices.getFusedLocationProviderClient(this)
    fusedLocation.lastLocation.addOnSuccessListener { location: Location? ->
        // Replace !! with a safe null check
        location?.let { validLocation ->
            val latLong = LatLng(validLocation.latitude, validLocation.longitude)
            myMap.addMarker(MarkerOptions().position(latLong).title("Found Location"))
            myMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLong, 10f))
        } ?: run {
            // Handle null location case with a user-friendly dialog
            MaterialAlertDialogBuilder(this)
                .setTitle("Location Unavailable")
                .setMessage("We couldn't fetch your current location. Please check if location services are enabled, or try moving around to refresh your location.")
                .setPositiveButton("Got it") { dialog, _ -> dialog.dismiss() }
                .show()
        }
    }
}

2. Don't Rely on lastLocation Alone

lastLocation only returns cached location data, which can be null. For reliable location data, use location updates to fetch a fresh location when the cached one is missing:

First, add the necessary variables and initialization in onCreate:

import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationResult
import android.content.Context
import android.content.Intent
import android.provider.Settings

private lateinit var locationRequest: LocationRequest
private lateinit var locationCallback: LocationCallback

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)

    // Initialize location request for real-time updates
    locationRequest = LocationRequest.create().apply {
        interval = 10000 // Update every 10 seconds
        fastestInterval = 5000 // Fastest update interval (5 seconds)
        priority = LocationRequest.PRIORITY_HIGH_ACCURACY // Use high accuracy for best results
    }

    // Define callback to handle location updates
    locationCallback = object : LocationCallback() {
        override fun onLocationResult(locationResult: LocationResult) {
            super.onLocationResult(locationResult)
            locationResult.lastLocation?.let { newLocation ->
                val latLong = LatLng(newLocation.latitude, newLocation.longitude)
                myMap.addMarker(MarkerOptions().position(latLong).title("Found Location"))
                myMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLong, 10f))
                // Stop updates once we get a valid location
                fusedLocation.removeLocationUpdates(locationCallback)
            }
        }
    }

    // Rest of your onCreate code...
}

Then update the button click listener to fall back to location updates when lastLocation is null:

binding.button2.setOnClickListener {
    // First check if location services are enabled
    if (!isLocationEnabled()) {
        MaterialAlertDialogBuilder(this)
            .setTitle("Location Services Disabled")
            .setMessage("Please enable location services to fetch your location.")
            .setPositiveButton("Go to Settings") { _, _ ->
                startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
            }
            .setNegativeButton("Cancel") { dialog, _ -> dialog.dismiss() }
            .show()
        return@setOnClickListener
    }

    // Check permissions as before
    val hasFineLocation = ActivityCompat.checkSelfPermission(
        this,
        Manifest.permission.ACCESS_FINE_LOCATION
    ) == PackageManager.PERMISSION_GRANTED
    val hasCoarseLocation = ActivityCompat.checkSelfPermission(
        this,
        Manifest.permission.ACCESS_COARSE_LOCATION
    ) == PackageManager.PERMISSION_GRANTED

    if (!hasFineLocation && !hasCoarseLocation) {
        ActivityCompat.requestPermissions(
            this,
            arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION),
            100
        )
        return@setOnClickListener
    }

    fusedLocation = LocationServices.getFusedLocationProviderClient(this)
    fusedLocation.lastLocation.addOnSuccessListener { location: Location? ->
        location?.let { validLocation ->
            val latLong = LatLng(validLocation.latitude, validLocation.longitude)
            myMap.addMarker(MarkerOptions().position(latLong).title("Found Location"))
            myMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLong, 10f))
        } ?: run {
            // No cached location—request real-time updates
            MaterialAlertDialogBuilder(this)
                .setTitle("Fetching Location")
                .setMessage("We're getting your current location now...")
                .setCancelable(false)
                .show()

            fusedLocation.requestLocationUpdates(
                locationRequest,
                locationCallback,
                Looper.getMainLooper()
            )
        }
    }
}

// Helper method to check if location services are enabled
private fun isLocationEnabled(): Boolean {
    val locationManager = getSystemService(Context.LOCATION_SERVICE) as android.location.LocationManager
    return locationManager.isProviderEnabled(android.location.LocationManager.GPS_PROVIDER) ||
            locationManager.isProviderEnabled(android.location.LocationManager.NETWORK_PROVIDER)
}

3. Key Takeaways

  • Never use !! with nullable location data—always handle null cases gracefully
  • lastLocation is unreliable for fresh or first-time location data; use location updates as a fallback
  • Always verify permissions and location service status before attempting to fetch location
  • Add user-friendly feedback for edge cases (like disabled location services or missing location data)

内容的提问来源于stack exchange,提问作者thebluepandabear

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 20:49:10