FusedLocationClient doesn't stop searching for gps after request - android

My FusedLocationProviderClient is not stopping after I call
fusedLocationClient.removeLocationUpdates(locationCallback);
The GPS location icon shows indefinitely in the notification bar until I manually terminate the service.
I am calling stopLocationUpdates in the onDestroy() method as well.
To start it, I am calling:
fusedLocationClient.requestLocatonUpdates(locationRequest, locationCallback, null);
locationCallback being:
locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
Location lastLocation = null;
for (Location location : locationResult.getLocations()) {
if (lastLocation != null) {
if (location.getTime() < lastLocation.getTime()) {
lastLocation = location;
}
} else {
lastLocation = location;
}
}
if (lastLocation != null) {
String msg1 = "Best location: http://www.google.com/maps/search/?api=1&query=" + lastLocation.getLatitude() + "%2C" + lastLocation.getLongitude();
sendSms(lastReceivedNumber, msg1);
}
stopLocationUpdates();
}
};
Here is stopLocationUpdates():
private void stopLocationUpdates() {
if (fusedLocationClient != null) {
fusedLocationClient.removeLocationUpdates(locationCallback);
}
fusedLocationClient = null;
}
I can't understand why it doesn't stop.
Any help appreciated.

Here is what I did:
private void startLocationUpdates() {
fusedLocationClient = new FusedLocationProviderClient(this);
locationRequest = new LocationRequest().setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
Location lastLocation = null;
for (Location location : locationResult.getLocations()) {
if (lastLocation != null) {
if (location.getTime() < lastLocation.getTime()) {
lastLocation = location;
}
} else {
lastLocation = location;
}
}
if (lastLocation != null) {
String msg1 = "Best location: http://www.google.com/maps/search/?api=1&query=" + lastLocation.getLatitude() + "%2C" + lastLocation.getLongitude();
sendSms(lastReceivedNumber, msg1);
}
stopLocationUpdates();
}
};
try {
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null);
} catch (SecurityException e) {
e.printStackTrace();
}
}
private void stopLocationUpdates() {
if (fusedLocationClient != null) {
fusedLocationClient.removeLocationUpdates(locationCallback);
}
fusedLocationClient = null;
locationRequest = null;
locationCallback = null;
}
I was only nulling the client, nulling everything seems to solve the issue.
Now all i have to do is call startLocationUpdates() and it takes care of itself, destroying everything afterwards.

Related

Get the CurrentLocation instead of LastKnownLocation

I made this code and it's working, but the location can only be retrieved if I open Google Maps before launching the app. I want to make my app detect my current location instead of the last known location. I found that there is a method called getCurrentLocation() that can be used to retrieve my location but I don't know what to put in the parameters. Please help me.
This is my code:
private void getLocation() {
//Check Permissions again
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ActivityCompat.checkSelfPermission(Reclamation.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(Reclamation.this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.INTERNET}, REQUEST_PERMISSION_LOCATION);
}
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Location LocationGps = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
Location LocationNetwork = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
Location LocationPassive = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);
if (LocationGps != null) {
double lat = LocationGps.getLatitude();
double longi = LocationGps.getLongitude();
latitude = String.valueOf(lat);
longitude = String.valueOf(longi);
} else if (LocationNetwork != null) {
double lat = LocationNetwork.getLatitude();
double longi = LocationNetwork.getLongitude();
latitude = String.valueOf(lat);
longitude = String.valueOf(longi);
} else if (LocationPassive != null) {
double lat = LocationPassive.getLatitude();
double longi = LocationPassive.getLongitude();
latitude = String.valueOf(lat);
longitude = String.valueOf(longi);
Toast.makeText(Reclamation.this, "Passive is not null :D", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(Reclamation.this, "Can't Get Your Location", Toast.LENGTH_SHORT).show();
}
Intent intent = new Intent(Reclamation.this, SetLocation.class);
intent.putExtra("latt", latitude);
intent.putExtra("lonn", longitude);
Toast.makeText(Reclamation.this, latitude + " " + longitude, Toast.LENGTH_SHORT).show();
startActivityForResult(intent, 3);
}
}
With
api 'com.google.android.gms:play-services-location:18.0.0'
U can use this methods
FusedLocationProviderClient fusedLocationClient;
FusedLocationProviderClient locationProviderClient = LocationServices.
getFusedLocationProviderClient(this);
//LOCATION AVAILABILITY
fusedLocationClient
.getLocationAvailability()
.addOnSuccessListener(new OnSuccessListener<LocationAvailability>() {
#Override
public void onSuccess(LocationAvailability locationAvailability) {
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
//LAST LOCATION
fusedLocationClient.getLastLocation()
.addOnSuccessListener(new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
//AND MORE...
fusedLocationClient
.requestLocationUpdates()
...

Show My Location on Button click in Android App

I have created a Floating Button on Maps. I would like to show the current location on Maps on Clicking that Button.
These looks on the end user as a process. But receiving the location and showing it on the map are 2 processes actually. I built a class because I needed it on my use case. But I can show you how to integrate with your case.
class LocationTracker(
val activity: FragmentActivity,
val locationTrackerListener: LocationTrackerListener
) {
private var fusedLocationClient: FusedLocationProviderClient =
LocationServices.getFusedLocationProviderClient(activity)
private var locationCallback: LocationCallback? = null
private var locationRequest: LocationRequest? = null
fun startLocationRequestProcess() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(
activity.applicationContext, Manifest.permission.ACCESS_COARSE_LOCATION
)
!= PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(
activity.applicationContext, Manifest.permission.ACCESS_FINE_LOCATION
)
!= PackageManager.PERMISSION_GRANTED
) {
activity.requestPermissions(
arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
), REQUEST_LOCATION_PERMISSION
)
} else {
getUserLocation()
}
} else {
getUserLocation()
}
}
fun getUserLocation() {
locationRequest = LocationRequest.create()?.apply {
interval = 10000
fastestInterval = 5000
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
//please check the docs for other constants. this is the minimum used
}
val builder = LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest!!)
val client: SettingsClient = LocationServices.getSettingsClient(activity)
val task: Task<LocationSettingsResponse> = client.checkLocationSettings(builder.build())
task.addOnSuccessListener {
updateLocation()
}
task.addOnFailureListener { exception ->
if (exception is ResolvableApiException) {
try {
exception.startResolutionForResult(
activity,
REQUEST_CHECK_LOCATION_SETTINGS
)
} catch (sendEx: IntentSender.SendIntentException) {
sendEx.printStackTrace()
}
}
}
}
fun updateLocation() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(
activity.applicationContext, Manifest.permission.ACCESS_COARSE_LOCATION
)
!= PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(
activity.applicationContext, Manifest.permission.ACCESS_FINE_LOCATION
)
!= PackageManager.PERMISSION_GRANTED
) {
activity.requestPermissions(
arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
), REQUEST_LOCATION_PERMISSION
)
} else {
requestLocationUpdates()
}
} else {
requestLocationUpdates()
}
}
private fun requestLocationUpdates() {
try {
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
if (locationResult == null) {
locationTrackerListener.onLocationError()
} else {
//you've got the response
locationTrackerListener.onLocationResult(locationResult)
}
}
}
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null)
} catch (securityException: SecurityException) {
securityException.printStackTrace()
}
}
fun removeLocationRequest() {
fusedLocationClient.removeLocationUpdates(locationCallback)
}
}
Class is set up: So onClick of your button:
fab.setOnClickListener{
//hope you have instatiated it
locationTracker.startLocationRequestProcess()
}
And later in the class you need the lat and long:
override fun onLocationResult(locationResult: LocationResult) {
for (location in locationResult.locations) {
addMarkerToMapAndPerhapsZoom(location.latitude, location.longitude)
}
}
The interface I am using:
interface LocationTrackerListener {
fun onLocationError()
fun onLocationResult(locationResult: LocationResult)
}
Excuse duplicate code for permissions but the IDE shows errors when refactoring that and I really hate it. You can also consider to get the last known location but the problem with that is that it gives null when the user is first time visitor to the app.
first create MyLocation class like this :
import java.util.Timer;
import java.util.TimerTask;
import android.annotation.SuppressLint;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
public class MyLocation {
Timer timer1;
LocationManager lm;
LocationResult locationResult;
boolean gps_enabled = false;
boolean network_enabled = false;
#SuppressLint("MissingPermission")
public boolean getLocation(Context context, LocationResult result) {
//I use LocationResult callback class to pass location value from MyLocation to user code.
locationResult = result;
if (lm == null)
lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
//exceptions will be thrown if provider is not permitted.
try {
gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
} catch (Exception ex) {
}
try {
network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch (Exception ex) {
}
//don't start listeners if no provider is enabled
if (!gps_enabled && !network_enabled)
return false;
if (gps_enabled)
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
if (network_enabled)
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
timer1 = new Timer();
timer1.schedule(new GetLastLocation(), 20000);
return true;
}
LocationListener locationListenerGps = new LocationListener() {
public void onLocationChanged(Location location) {
timer1.cancel();
locationResult.gotLocation(location);
lm.removeUpdates(this);
lm.removeUpdates(locationListenerNetwork);
}
public void onProviderDisabled(String provider) {
}
public void onProviderEnabled(String provider) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
LocationListener locationListenerNetwork = new LocationListener() {
public void onLocationChanged(Location location) {
timer1.cancel();
locationResult.gotLocation(location);
lm.removeUpdates(this);
lm.removeUpdates(locationListenerGps);
}
public void onProviderDisabled(String provider) {
}
public void onProviderEnabled(String provider) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
class GetLastLocation extends TimerTask {
#SuppressLint("MissingPermission")
#Override
public void run() {
lm.removeUpdates(locationListenerGps);
lm.removeUpdates(locationListenerNetwork);
Location net_loc = null, gps_loc = null;
if (gps_enabled)
gps_loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (network_enabled)
net_loc = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
//if there are both values use the latest one
if (gps_loc != null && net_loc != null) {
if (gps_loc.getTime() > net_loc.getTime())
locationResult.gotLocation(gps_loc);
else
locationResult.gotLocation(net_loc);
return;
}
if (gps_loc != null) {
locationResult.gotLocation(gps_loc);
return;
}
if (net_loc != null) {
locationResult.gotLocation(net_loc);
return;
}
locationResult.gotLocation(null);
}
}
public static abstract class LocationResult {
public abstract void gotLocation(Location location);
}
}
then use it in your googleMap class :
floatingButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& context.checkSelfPermission(
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
context.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
} else {
MyLocation.LocationResult locationResult = new MyLocation.LocationResult() {
#Override
public void gotLocation(Location location) {
if (location != null) {
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(latLng, 14);
mGoogleMap.animateCamera(update);
}
}
};
MyLocation myLocation = new MyLocation();
myLocation.getLocation(this, locationResult);
}
}
});
and do not forget to add permission ACCESS_FINE_LOCATION in your AndroidManifest :
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

FusedLocationProviderClient accuracy returns 1500 on some device

I am using FusedLocationProviderClient to trace location and I want to get the best location by using getAccuracy() method. I checked this method on some devices and it returns 1500 and sometimes 1700 while it has to be less than a few meters(less than 12). Why is this happening and what should I do?
Thanks in Advance.
My code:
mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
Location location = locationResult.getLastLocation();
float acc = location.getAccuracy();
if (location != null && location.getAccuracy() < 10){
if(preLocation == null){
preLocation = location;
locationChanged(location);
sendLocation(location.getLatitude(), location.getLongitude());
}else if (preLocation.getLatitude() != location.getLatitude() && preLocation.getLongitude() != location.getLongitude()) {
// Logic to handle location object
locationChanged(location);
preLocation = location;
}
}
}
};
Try to set locationRequest priority to High Accuracy like this
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
//Location Permission already granted
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
}
} else {
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
}
}
LocationCallback mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
for (Location location : locationResult.getLocations()) {
//Do what you want with the location here
}
}
};

FusedLocationProvider return null

I used fusedlocation provider client for get device location.But if location setting off my phone and open location setting with locationServices. getSettingsClient fused location provider return null
final Task<Location> locationTask = fusedLocationProviderClient.getLastLocation();
locationTask.addOnSuccessListener((Activity) context, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if (location != null) {
lastKnownLocation = location;
map.moveCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(lastKnownLocation.getLatitude(),
lastKnownLocation.getLongitude()), Constants.DEFAULT_ZOOM));
LatLng position = new LatLng(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude());
HashMap<String, String> adressInfo = MapUtility.getAddressGeocoderObject(context, position);
MapUtility.moveCamera(context, map, position, Constants.DEFAULT_ZOOM,
adressInfo.get("addressFeatureName"), adressInfo.get("remainAdress"));
} else {
Toast.makeText(context, "null", Toast.LENGTH_LONG).show();
//map.getUiSettings().setMyLocationButtonEnabled(false);
}
solved my problem when update fusedLocation provider
private void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(10*1000);
mLocationRequest.setFastestInterval(10*1000);
mLocationRequest.setSmallestDisplacement(10);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
private void createLocationCallback(){
locationCallback=new LocationCallback(){
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
//code here
}
};
}
and if location null update fused location provider
public void getDeviceLocation() {
try {
final Task<Location> locationTask = fusedLocationProviderClient.getLastLocation();
locationTask.addOnSuccessListener((Activity) context, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if (location != null) {
lastKnownLocation = location;
if(map==null){
Toast.makeText(context,"map null",Toast.LENGTH_LONG).show();
return;
}
map.moveCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(lastKnownLocation.getLatitude(),
lastKnownLocation.getLongitude()), Constants.DEFAULT_ZOOM));
LatLng position = new LatLng(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude());
HashMap<String, String> adressInfo = MapUtility.getAddressGeocoderObject(context, position);
assert adressInfo != null;
MapUtility.moveCamera(context, map, position, Constants.DEFAULT_ZOOM,
adressInfo.get("addressFeatureName"), adressInfo.get("remainAdress"));
} else {
createLocationRequest();
createLocationCallback();
fusedLocationProviderClient.requestLocationUpdates(mLocationRequest,locationCallback,Looper.myLooper());
}
}
});
locationTask.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d(Constants.PlacesTag, "Current location is null. Using defaults.");
}
});
} catch (SecurityException e) {
Log.e("Exception: %s", e.getMessage());
}
}

How to get just one location with fused location client?

What I want is to get just one fresh location and remove location updates after getting first location update and add it to realm but the problem am facing is getting more than 100 locations sometimes in a single update and executing 100 transactions in realm crash app
public void getCurrentLocation(final Context context) {
LocationRequest mLocationRequest;
final LocationCallback mLocationCallback;
final FusedLocationProviderClient mFusedLocationClient;
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(context);
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(60000);
mLocationRequest.setFastestInterval(60000);
mLocationRequest.setNumUpdates(1);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult)
{
if (locationResult == null)
{
return;
}
mFusedLocationClient.removeLocationUpdates(this);
Location tempLocation = locationResult.getLastLocation();
if (locationResult.getLocations().size() > 0)
{
tempLocation = locationResult.getLocations().get(0);
}
if(tempLocation != null )
{
RealmManager.writeLocationInRealm(context, tempLocation, true, 0);
}
}
};
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, null);
}
You can achieve this via below code
This code is in Kotlin
private var fusedLocationClient: FusedLocationProviderClient?=null
in Your onCreate()
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this#YourActivity)
fusedLocationClient!!.lastLocation
.addOnSuccessListener { location: Location? ->
//Your lattitude location!!.latitude
//Your Longitude location.longitude
}
I faced the same problem and this is how I solve it in kotlin
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
super.onLocationResult(locationResult)
if (locationResult.lastLocation != null && locationResult.lastLocation.latitude > 0 && locationResult.lastLocation.longitude > 0) {
UserLocationObject.lastLocation = locationResult.lastLocation
fusedLocationClient.removeLocationUpdates(locationCallback)
}
}
}

Categories

Resources