问题
Update 2
I had a talk with a google engineer on Google I/O '18. He told me that I can trust the fusedLocationProvider. If he marks the last known location with a new timestamp the user is probably still at the same location.
I'd like to do a few tests with a "moving" device in the future to prove this statement.
Original Question
I'm requesting the last known location from the FusedLocationProviderClient
with getLastLocation()
and want to check if the last known location is older than 5 minutes to start a new location request instead.
During my testing i discovered a weird behavior with the locations elapsedRealtimeNanos
which should be used to compare.
For testing purpose I'm requesting the last known location every second in a simple Java Thread. When the location is received I check the elapsedRealtimeNanos and compare them to SystemClock.elapsedRealtimeNanos()
. In most cases the age of the last known location is set to SystemClock.elapsedRealtimeNanos()
as well, so the difference is nearly 0. Which means, that the FusedLocationProvider tells me that the fix of the last known location was right now, which makes age checks not reliable.
This behavior is weird enough but its getting worse.
When I start a parallel location Request during my testing sessions or launch Google Maps, the elapsedRealtimeNanos
of the last known location stops growing and is only updated to a newer time when a "real" new location was found. Which should be the default behavior that I would expect.
I observed this behavior during different Location Settings like HIGH_ACCURACY and SENSORS_ONLY.
Does this mean, that checking the age of the last known location is impossible? Can anyone explain the behavior?
Update 1
Same behavior with location.getTime()
Code Snippets:
@Override void getLastKnownLocation() {
try {
mLocationClient.getLastLocation().addOnCompleteListener(new OnCompleteListener<Location>() {
@Override
public void onComplete(@NonNull Task<Location> task) {
try {
Location location = task.getResult();
if (location != null) {
location.getElapsedRealtimeNanos()
//Compare to SystemClock.elapsedRealtimeNanos();
...
and (I know its messy)
new Thread(){
@Override public void run() {
locationFinder.getLastKnownLocation();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
run();
}
}.start();
Location Update Request
public PlayServicesLocationFinder(Context context){
mLocationClient = LocationServices.getFusedLocationProviderClient(context);
}
@Override
public void getLocationUpdates() {
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setInterval(60000);
locationRequest.setFastestInterval(15000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationClient.requestLocationUpdates(locationRequest, continuousUpdatesLocationListener, null);
}
回答1:
Maybe I can recommend you to try other way to get a "fresh" coordinate, which seems to be your main goal with your code. Maybe you can try:
- First get the LastKnownLocation.
- Once you have the LastKnownLocation. You can began to requestLocationUpdates() and once you have a new coordinate that is DIFFERENT from lastKnownLocation, then that one is your "fresh" coordinate. You can even implement accuracy controls in order to get "accurate and freshier" coordinates.
I´ve used the previous scheme and it works perfect in order to get the current position without validating Location GPS time (getTime()).
NOTE: I´m aware that this is not battery friendly, but you can control the number of updates, interval time, max wait time in the LocationRequest in order to keep the battery consumption to the minimum.
回答2:
There is a way around to resolve this requirement. You will be calculating savedLocation with updatedLocation, whether to store new Location or not. Two attribute can help you out with this calculation.
- Distance between the two locations.
- Time of the locations fetched. (your requirement)
Firstly you have to store location return with
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
mGoogleApiClient);
then compare it with next fetched location(both attribute would give you better trace to manage device location updates), then decide new fetched location should be replaced to stored location or not. for this you have write your logics, thought I can share some code which may help you out.
private boolean isTimeToUpdateLocation(Location newlocation) {
int LOCATION_ALERT_FREQUENCY = 60000; //1 * 60000; // 1 minute
long timeDelta = System.currentTimeMillis() - newlocation.getTime();
return (timeDelta >= LOCATION_ALERT_FREQUENCY);
}
There is a small piece of code regarding location update with respect to distance
int LOCATION_DEVIATION = 1000; // 1 KM
public boolean shouldUpdateNewLocation(Location location) {
Location prevLocation = getLastStoredLocation();
boolean shouldUpdateToServer = false;
if (prevLocation != null) {
if (prevLocation.distanceTo(location) > LOCATION_DEVIATION)
shouldUpdateToServer = true;
}
return shouldUpdateToServer;
}
I hope you can now resolve the issue you are facing.
来源:https://stackoverflow.com/questions/49034473/fusedlocationproviderclient-getlastlocation-elapsedrealtimenanos-mostly-current