I am trying to ask for user location permission but I need to set some kind of listener to the user response otherwise, I cant get the user location and the app crashes due to null pointer exception.
This are the functions I am using to get and set the location
private void setLocation() {
if (ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, 44);
}
LocationManager locationManager;
locationManager = (LocationManager) getSystemService(ScoreActivity.this.LOCATION_SERVICE);
Location location = locationManager.getLastKnownLocation(locationManager.NETWORK_PROVIDER);
onLocationChanged(location);
}
#Override
public void onLocationChanged(#NonNull Location location) {
locationDetails=new LatLng(location.getLatitude(),location.getLongitude());
}
I'm trying to create an android app that gives accurate location (1m or less) indoors. It seems the recommended way is to use the
a FusedLocationProviderClient
However the current horizontal accuracy I'm getting is between 5m and 15m for longitude and latitude while the vertical accuracy is often up to 50m out.
Not sure if it makes a difference but the the test device is an HTC U11?
I've updated google play service location com.google.android.gms:play-services-location:17.0.0
I've included android.permission.ACCESS_FINE_LOCATION in my app manifest and locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); in the location request.
I've got some code in there which turns the GPS on.
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(3 * 1000); // 3 seconds
locationRequest.setFastestInterval(1 * 1000); // 3 seconds
new GpsUtils(this).turnGPSOn(new GpsUtils.onGpsListener() {
#Override
public void gpsStatus(boolean isGPSEnable) {
// turn on GPS
isGPS = isGPSEnable;
}
});
locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) {
return;
}
for (Location location : locationResult.getLocations()) {
if (location != null) {
wayLatitude = location.getLatitude();
wayLongitude = location.getLongitude();
Lat.setText(Double.toString(location.getLatitude()));
Longs.setText(Double.toString(location.getLongitude()));
Acc.setText(String.format("%.2f", location.getAccuracy()));
if(location.hasAltitude()) {
Alt.setText(String.format("%.2f",location.getAltitude() - 108));
VAcc.setText(String.format("%.2f",location.getVerticalAccuracyMeters()));
}
else {
Alt.setText("Lost");
VAcc.setText("Lost");
}
SendToBackend(wayLatitude,wayLongitude, location);
if (!isContinue && mFusedLocationClient != null) {
mFusedLocationClient.removeLocationUpdates(locationCallback);
}
}
}
}
};
According to google it should be possible to get below 1m accuracy indoors. a link.
Thanks in advance :-)
It is OK when I open the GPS long times, I can get my current location, but when I turn off and then turn on the GPS, it returns null as the current location. I need to refresh or reinstall the app to make the current location work. Is it possible to get the location after a few seconds of turning on the GPS?
Here is my code:
client = LocationServices.getFusedLocationProviderClient(this);
LocationManager locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
if(!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
intent.addCategory(Intent.CATEGORY_DEFAULT);
startActivity(intent);
finish();
} else {
if (ActivityCompat.checkSelfPermission(MapsActivity.this, ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ) {
return;
}
client.getLastLocation().addOnSuccessListener(MapsActivity.this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if(location!= null){
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
});
}
I found out that I need to use requestsLoctionUpdates, but I cannot find any tutorial that explains me how to do it in the new version of android studio (Location : 11.8.0). Can anyone can tell me how to use this code?
I have been working on google maps and below is the method I am using to initialize the map. Surprisingly, mapFragment.getMapAsync() method is not getting executed so googleMaps object is still null after calling getMapAsync().
// Initialize the google map
void initMap() {
Log.d(MAPSACTIVITY_TAG, "Initializing google map");
mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.maps_fragment);
mapFragment.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap gMap) {
Log.d(MAPSACTIVITY_TAG,"Maps is ready");
googleMap=gMap;
}
});
Log.d(MAPSACTIVITY_TAG,"Value of google maps is "+googleMap);
//This will get device location, set GoogleAPIClient and set mundu marker
if (isLocationPermissionGranted) {
getDeviceLocation();
buildGoogleApiClient();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(context, "Sorry! App requires location permission", Toast.LENGTH_SHORT).show();
return;
}
googleMap.setMyLocationEnabled(true);
//this will get client's location and set client's marker
geoLocateClient();
} else
Log.d(MAPSACTIVITY_TAG, "Location permission is not given");
}
Here is the Logcat snapshot:
Please notice, Log statement in the getMapAsync is never executed. Can anyone help me with this?
Edit:
Someone marked this question as a duplicate of What is a NullPointerException, and how do I fix it? Please notice this question is about how and when onMapReady() method is called by getMapAync() (its nothing related to the null pointer exception)
You should move code that uses variable googleMap inside onMapReady(...) { ... } method because getMapAsync(...) is asynchronous and onMapReady(...) will be called later in a different thread after Maps has responded.
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 3 years ago.
Would you please explain me why getLongitude and getLatitude returns a NullPointerException?
The truth is the problem already has been solved, but there's one thing that is bugging me for this might be asked by our thesis coordinator. The situation is that I have to get the user's current coordinates (latitude and longitude). I've decided to use FusedLocationClient.getLastLocation() in order to get the coordinates.
mFusedLocationClient = getFusedLocationProviderClient(this);
//app already crashes once the line below is executed
mFusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if(location != null){
//myLocation is an instance variable of this class
myLocation = location;
}else{
Toast.makeText(PlaceCategoriesActivity.this, "Location fetch failed!", Toast.LENGTH_SHORT).show();
}
}
});
latitude = myLocation.getLatitude(); //this line throws NullPointerException
longitude = myLocation.getLongitude();
The app seems to compile fine but then it crashes, upon inspecting by adding a breakpoint for debugging on myLocation.getLatiude() and myLocation.getLongititude(), it turns out that this method invokes a null pointer exception, which for me is weird because myLocation already has referenced the location object brought by the onSuccess method of the addOnSuccessListener.
I've already solved the problem by moving the last two lines of code and putting in within the listener like this:
mFusedLocationClient = getFusedLocationProviderClient(this);
mFusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if(location != null){
myLocation = location;
//moved the 2 lines of code and it now works
latitude = myLocation.getLatitude();
longitude = myLocation.getLongitude();
}else{
Toast.makeText(PlaceCategoriesActivity.this, "Location fetch failed!", Toast.LENGTH_SHORT).show();
}
}
});
//Toast returns a value of 0 on latitude and 0 on longitude
Toast.makeText(this, "Lat: " + latitude + "Long: + " + longitude, Toast.LENGTH_SHORT).show();
The funny thing is that the longitude and latitude is shown on the Toast and both has a value of 0.
which for me is weird because myLocation already has referenced the location object brought by the onSuccess method of the addOnSuccessListener
Let's simplify your first code listing:
mFusedLocationClient = getFusedLocationProviderClient(this);
latitude = myLocation.getLatitude(); //this line throws NullPointerException
longitude = myLocation.getLongitude();
Here, myLocation has not been assigned a value. If you have not assigned a value to myLocation in preceding lines, myLocation will be null, and you will get a NullPointerException.
Now, let's restore some lines to that code snippet:
mFusedLocationClient = getFusedLocationProviderClient(this);
//app already crashes once the line below is executed
mFusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
}
});
latitude = myLocation.getLatitude(); //this line throws NullPointerException
longitude = myLocation.getLongitude();
The last word in addOnSuccessListener() is "listener". This suggests that you are registering an event listener. Usually — though not always — such a listener is only invoked on future events. It is likely that onSuccess() will not be called until sometime later. However, your program keeps running, and you then try calling getLatitude() on myLocation. Since we still have not done anything to assign a value to myLocation, it will be null, and you will crash with a NullPointerException.
And so while your first code snippet does assign a value to myLocation, you as a programmer have to assume that it will not do so until some time in the future (e.g., when we get a new location fix). Do not attempt to use myLocation until onSuccess() has assigned it a value.
you should not add these lines after addOnSuccessListener:
latitude = myLocation.getLatitude(); //this line throws NullPointerException
longitude = myLocation.getLongitude();
because you have to wait until mFusedLocationClient successfully gets LastLocation
i.e. move these lines into onSuccess method!
As for the reason of the nullPointerException it's because myLocation has not yet been initialized !
You simply need to display the location when you get it, not before. That's said, just put the display code in the listener.
mFusedLocationClient = getFusedLocationProviderClient(this);
// Register a listener, that will be called when the location will be available
mFusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if (location != null) {
// We have a location!
myLocation = location;
// So print it now
latitude = myLocation.getLatitude();
longitude = myLocation.getLongitude();
Toast.makeText(PlaceCategoriesActivity.this, "Lat: " + latitude + "Long: + " + longitude, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(PlaceCategoriesActivity.this, "Location fetch failed!", Toast.LENGTH_SHORT).show();
}
}
});
// Loading, as we wait for listener to be called
Toast.makeText(this, "Loading...", Toast.LENGTH_SHORT).show();
Example:
class LocationApi : Service(), GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
private var myGoogleApiClient: GoogleApiClient? = null
private val myLocationRequest = LocationRequest.create()
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
myGoogleApiClient = GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addOnConnectionFailedListener(this)
.addConnectionCallbacks(this)
.build()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
myGoogleApiClient?.connect()
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
myGoogleApiClient?.disconnect()
if (myGoogleApiClient != null && myGoogleApiClient?.isConnected!!) {
LocationServices.getFusedLocationProviderClient(this).removeLocationUpdates(locationCallBack)
}
super.onDestroy()
}
override fun onConnected(bundle: Bundle?) {
//here u can define your interval and priority
// request locations, check permissions ok
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
LocationServices.getFusedLocationProviderClient(this).requestLocationUpdates(myLocationRequest, locationCallBack, Looper.myLooper())
}
}
override fun onConnectionSuspended(p0: Int) {
}
override fun onConnectionFailed(p0: ConnectionResult) {
}
override fun onLocationChanged(location: Location?) {
//saving location on DB
LocationInteractor(location)
}
private val locationCallBack = object : LocationCallback() {
override fun onLocationResult(location: LocationResult) {
super.onLocationResult(location)
onLocationChanged(location.lastLocation)
}
}
}