It gives me this error (double android.location.Location.getLatitude()' on a null object reference)
I tried many many different solutions but all of the same, I know that fusedLocationClient.lastLocation it just gives the last location from other apps, but I don't want that, I want to get the current location without it because it gives null? so how to fix this and get current Location???
import android.Manifest
import android.content.ContentValues.TAG
import android.content.Context
import android.content.pm.PackageManager
import android.location.LocationManager
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import com.firebase.geofire.GeoFire
import com.firebase.geofire.GeoLocation
import com.firebase.geofire.GeoQueryEventListener
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.firebase.database.DatabaseError
import com.google.firebase.database.FirebaseDatabase
import com.moapp.guardaroundd.R
import com.moapp.guardaroundd.databinding.FragmentMapBinding
import com.moapp.guardaroundd.utils.Constants.DEFAULT_ZOOM
import com.moapp.guardaroundd.utils.Constants.LOCATION_PERMISSION_REQUEST_CODE
import com.moapp.guardaroundd.utils.createAlertEnableLocation
class MapFragment : Fragment(), OnMapReadyCallback {
private lateinit var mMap: GoogleMap
private lateinit var binding: FragmentMapBinding
private lateinit var fusedLocationClient: FusedLocationProviderClient
private var mLocationPermissionsGranted = false
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
binding = FragmentMapBinding.inflate(layoutInflater)
val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireActivity())
return binding.root
}
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
getLocationPermission()
}
private fun isLocationEnabled(): Boolean {
val locationManager =
activity?.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
return locationManager!!.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(
LocationManager.NETWORK_PROVIDER
)
}
private fun moveCamera(latLng: LatLng) {
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, DEFAULT_ZOOM))
}
private fun getLocation() {
if (isLocationEnabled()) {
try {
fusedLocationClient.lastLocation.addOnSuccessListener {
moveCamera(LatLng(it.latitude, it.longitude))
mMap.isMyLocationEnabled = true
}
} catch (ex: SecurityException) {
}
} else {
//Custom alert
createAlertEnableLocation(requireContext())
}
}
private fun getLocationPermission() {
if (ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.ACCESS_FINE_LOCATION
)
== PackageManager.PERMISSION_GRANTED
) {
mLocationPermissionsGranted = true
getLocation()
} else {
ActivityCompat.requestPermissions(
requireActivity(), arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
LOCATION_PERMISSION_REQUEST_CODE
)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
mLocationPermissionsGranted = false
when (requestCode) {
LOCATION_PERMISSION_REQUEST_CODE -> {
// If request is cancelled, the result arrays are empty.
if (grantResults.isNotEmpty() &&
grantResults[0] == PackageManager.PERMISSION_GRANTED
) {
mLocationPermissionsGranted = true
}
}
}
}
CodePudding user response:
The easiest way to avoid the null location
would be to launch the Google Maps App and press my location button. You then go back to your app and fusedLocationClient.lastLocation
will this time give you non-null device last location.
Since you clearly don't prefer this then you need to work with Location Updates.
For that I would tweak you getLocation()
code a little bit.
private fun getLocation() {
// last known location from fusedLocationProviderClient returned as a task
fusedLocationProviderClient.lastLocation
//check if the last location is null
.addOnSuccessListener { lastLoc ->
if (lastLoc != null) {
// initialize lastKnownLocation from fusedLocationProviderClient
lastKnownLocation = lastLoc
moveCamera(LatLng(lastLoc.latitude, lastLoc.longitude))
} else {
//if null trigger location update to get location
fusedLocationProviderClient.requestLocationUpdates(
locationRequest, locationCallback, Looper.getMainLooper()
)
}
// in case of error Toast the error in a short Toast message
}
.addOnFailureListener {
Toast.makeText(requireActivity(), "${it.message}", Toast.LENGTH_SHORT).show()
}
}
I would also need to bring in the LocationRequest
and Location Callback
into the play.
class MapFragment : Fragment(), OnMapReadyCallback { .......
// LOCATION COMPONENTS
private lateinit var lastKnownLocation: Location
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
private val locationRequest =
LocationRequest().apply {
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
interval = TimeUnit.SECONDS.toMillis(10)
fastestInterval = TimeUnit.SECONDS.toMillis(1)
}
private val locationCallback =
object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
super.onLocationResult(locationResult)
if (locationResult != null) {
lastKnownLocation = locationResult.lastLocation
//call the above getLocation() again to move camera
getLocation()
}
}
}
So whenever the last known location from the fusedClient is null, an update is triggered and the Camera position is moved.