thebluepandabear
thebluepandabear

Reputation: 571

GetFusedLocationProviderClient returning null latitude and longitude values for users' location

For an app I'm making, I need to get the users' location which will then be displayed on the map.

To achieve this, I am using LocationServices.getFusedLocationProviderClient() in the code below.

When I get the location value in addOnSuccessListener, the latitude and longtitude values are null for some reason, so I'm getting a 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
    }

}

When I run the app, I get the following exception:

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)

And yes, I have said yes to all permissions when I ran the app for the first time.

If this question is poorly written or a duplicate, please let me know as I strive to create good and well-structured questions.

Upvotes: 1

Views: 1579

Answers (6)

kgmk
kgmk

Reputation: 71

It looks like you request the permission(ActivityCompat.requestPermissions(...)) but never handle the permission request(you need to override onRequestPermissionsResult(...)). More info on that: https://developer.android.com/training/permissions/requesting#manage-request-code-yourself

Or you can switch to the new method to allow the system to manage the request code: https://developer.android.com/training/permissions/requesting#allow-system-manage-request-code

One last thing, in some cases getLastLocation() can return null, in that case I call getCurrentLocation() which always returns new fresh device location, more info here: https://developer.android.com/training/location/retrieve-current#BestEstimate

Upvotes: 0

Nadeem
Nadeem

Reputation: 93

I had the same issue

  1. check if the gps is turned on on the device
  2. may be because of the billing of the google maps api key you are using check all of this some times the error log shows the problem of google maps billing issue

Upvotes: 0

quealegriamasalegre
quealegriamasalegre

Reputation: 3258

I have faced this isue as well especially when i first install my app on a device. there are two things that you can try out that i think will help:

one is trying to open the google maps app and waiting for it to get a fix and then go on and open your app. this should provide your fused location provider client a last location that it can look up. check this answer for reference

the second is going a step further and requesting location updates using the provider. If you only need a single location fix you can then go on and deregister it once you get the first one. I am doing this for my app and usually last location is only null the first time i use the app after installation. after that it usually works. this is probably what you should do anyway as you cant expect your users to turn on google maps before using your app.

and just to be safe, be aware that fusedlocationproviderclient sometimes stops working or behaves weirdly when you have pending google services updates on your device. so go ahead and make sure your device is up to date in this regard.

Upvotes: 1

First of all, the correct procedure not to get null when initializing user coordinates to map is to initialize the map on onConnected() callback instead of onCreate() in an activity or fragment, lastLocation can be null.

You can use REQUEST_CODE_ASK_PERMISSIONSto handle the callback if not using location observer, the location observer basically would look something like this

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

I had the same case back in the days, my code was something like this on permission callback :

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

Basically on Permission granted, it will get your location and you can choose it whether you wanna use it to addMarker or anything else.

Upvotes: 0

CMMIW, your code went wrong around here

val latLong = LatLng(location!!.latitude, location.longitude)
                myMap.addMarker(MarkerOptions().position(latLong).title("Found Location"))

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

First of all, your location can be null whereas coordinates can't, so make sure to put null safety on coordinates(latitude and longitude).

You can use REQUEST_CODE_ASK_PERMISSIONSto handle the callback if not using location observer, the location observer basically would look something like this

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

I had the same case back in the days, my code was something like this on permission callback :

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

Basically on Permission granted, it will get your location and you can choose it whether you wanna use it to addMarker or anything else.

Upvotes: 0

Per.J
Per.J

Reputation: 1388

lastLocation can be null for several reasons. They are listed here https://developer.android.com/training/location/retrieve-current#last-known

Upvotes: 0

Related Questions