I have registered my LocationManager for location updates, every 10 seconds
mgr.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10 * 1000, 50, this);
But the onLocationChanged callback returns a location every 10 secs, which(the location) is more than 2 hours old. And that time-stamp is never changing.
The problem is:
2 hours back I was in a complete different location(home) where I used the device on a wifi. Now currently I am in some other location(office) on a different wifi where my application shows my current location as home. Same thing happened at home yesterday, when it was showing office as my current location. It got to work(started showing correct location) when I closed my app, opened FourSquare app and re-opened my app.
Complete Code:
public class LocationService extends Service implements LocationListener {
public static double curLat = 0.0;
public static double curLng = 0.0;
private LocationManager mgr;
private String best;
private Location location;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mgr = (LocationManager) getSystemService(LOCATION_SERVICE);
best = LocationManager.NETWORK_PROVIDER;
location = mgr.getLastKnownLocation(best);
if (location != null) {
dumpLocation(location);
mgr.requestLocationUpdates(LocationManager.GPS_PROVIDER,
10 * 1000, 50, this);
}
return START_NOT_STICKY;
}
}
private void dumpLocation(Location l) {
SimpleDateFormat s = new SimpleDateFormat("dd/MM/yyyy:hh:mm:ss",
Locale.ENGLISH);
String format = s.format(l.getTime());
//The above time is always 28/03/2013:09:26:41 which is more than 2 hrs old
curLat = l.getLatitude();
curLng = l.getLongitude();
}
#Override
public void onLocationChanged(Location location) {
dumpLocation(location);
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}
Being started in an Activity this way:
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent i = new Intent(this, LocationService.class);
pi = PendingIntent.getService(this, 0, i,
PendingIntent.FLAG_UPDATE_CURRENT);
am.cancel(pi);
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(), 10000, pi);
Permissions in manifest:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
I can get the correct location now, by opening some other location based app like Maps, Navigator, Foursquare etc.., But why my app isn't able to get a new/fresh fix from the provider.
Thank You
You are getting old location because of this line
location = mgr.getLastKnownLocation(best);
because if GPS is not enabled then it will show you the old location . So remove this code It will work like a champ
You can also refer to this library
https://github.com/nagendraksrivastava/Android-Location-Tracking-Library
On the basis of your comments I have edited the answer Okay Let me explain line by line
location = mgr.getLastKnownLocation(best); it will give you object of last know location then it will go inside if condition and it will call dumplocation and will get last location data and after that you called
mgr.requestLocationUpdates(LocationManager.GPS_PROVIDER,
10 * 1000, 50, this);
but suppose GPS provider is disabled then it will not fetch new location so you will get old location only . So either you can change it like
if(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
{
locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER,new NagendraSingleLocationListener(),null);
}
else
{
locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER,new NagendraSingleLocationListener(),null);
}
I think because you cancel your pending intent right away, thus the requestLocationUpdate would not start update before you cancel. Why don't you sleep may be for 2 second before cancel.
From my experience android will give you a location when you request the updates even if gps has not enough sattelites to work. So even if gps is on - if you are inside or in a location that is bad (like under a bridge) android will deliver an old fix to you. Can be a very old one indeed.
The only thing I found to be working 100% is to generelly not use the first position but only remember the time. When new positions arrive you can check that the time is newer than the last. If you want to only use very precise positions you may also need to check that location.getAccuracy() is low (the lower the better).
I use gps to get my timestamps for a soap interface as the android clock can be very off sometimes and this was the only way for me to get a valid time from gps.
Related
Right, the situation is as follows;
We have developed an app that checks the location of the user every 5-10 minutes for location specific content. To do so, I've created a Service to stick to the background (so it can update even when the app isn't directly in the foreground) in which a LocationController is created to check the latest known location. When it's finished, it cleans up and the location is sent to a database (which is a necessity for this concept).
This all works fine, as long as I check the location with GPS_PROVIDER. However, when I switch it around to NETWORK_PROVIDER, it may check the location once more before dying completely.
I've tried multiple options to prevent this problem, but nothing seems to be working with the update service when I swap that 1 setting.
Here are a few snippets which should be relevant to the service:
UpdateService:
#Override
public void onCreate() {
super.onCreate();
Log.d("Debug", "Created service");
PowerManager mgr = (PowerManager)getSystemService(Context.POWER_SERVICE);
wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
wakeLock.acquire();
IntentFilter filter = new IntentFilter();
filter.addAction(UPDATE_ACTION);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("Starting", "Starting Service");
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mAlarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(UPDATE_ACTION);
alarmManagerPendingIntent = PendingIntent.getBroadcast(this, 0, i, 0);
alarmManagerPendingIntent.cancel();
mAlarmManager.cancel(alarmManagerPendingIntent);
mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
AlarmManager.INTERVAL_FIFTEEN_MINUTES,
AlarmManager.INTERVAL_FIFTEEN_MINUTES,
alarmManagerPendingIntent);
mLocationController = new LocationController(this, this);
updateHandler = new Handler();
return START_STICKY;
}
LocationController:
private LocationListener locationListener = new LocationListener() {
private boolean didSendLocation;
public void onLocationChanged(Location location) {
mLastLocation = location;
mCallback.locationUpdate(location,false);
didSendLocation = true;
}
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.d("Debug", "Status changed: "+status);
Location _lastLocation = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
Log.d("Debug", "Last location: "+_lastLocation);
if(!didSendLocation)
{
mCallback.locationUpdate(_lastLocation,false);
}
didSendLocation = false;
}
public void onProviderEnabled(String provider) {
Log.d("Debug", "Provider Enabled");
}
public void onProviderDisabled(String provider) {
Log.d("Debug", "Provider disabled");
}
};
public LocationController(Context mContext, LocationControllerCallback callback) {
this.mContext = mContext;
mCallback = callback;
Log.d("Debug", "Created LocationController");
mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 300000, 100, locationListener);
mLastLocation = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
mCallback.locationUpdate(mLastLocation,true);
}
So, the code works as it is now, but when I swap:
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 300000, 100, locationListener);
with
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 300000, 100, locationListener);
It will no longer update. Any ideas?
When you use this to get location updates:
mLocationManager.requestLocationUpdates(...)
you don't need AlarmManager methods as the first parameter of the requestLocationUpdates method already acts as a "timer". See here for more info.
Also, you may need to include the following directives in your AndroidManifest.xml file:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.CONTROL_LOCATION_UPDATES"/>
Without these permissions, the requestLocationUpdates method may not work as you expected regardless of which provider you use.
UPDATE 1:
I would have your LocationController class initialiased in a Service, for example:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
this.mLocationController = new LocationController(this);
return Service.START_NOT_STICKY;
}
Then, start the above Service in the onResume method of an activity (MainActivity or another activity in your project), and pause the Service in the onPause method of the same activity.
If its specific to the NETWORK_PROVIDER, you may be seeing this bug:
https://code.google.com/p/android/issues/detail?id=57707
Original bug report included the Samsung Galaxy S3 as an affected device.
To help troubleshoot - you may also want to try selecting the NETWORK_PROVIDER in the GPS Benchmark app (full disclosure - its my app) to see if this app exhibits the same behavior. If so, its likely an issue with the device.
If you determine you're seeing the above issue, please be sure to star it on the issue page if you'd like to see it fixed.
I've solved the problem by switching to the Google Play Fused Location provider. A more detailed post around this can be found here: https://stackoverflow.com/a/19282976/3532181
Sadly the standard network provider just seemed too unreliable when it came to updates, ranging from an update within 8 minutes to hours before a new update was sent to the app.
I had a similar issue. I was able to fix this by adding the required permissions. The issue is related to new background service limitations.
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
Check this documentation for better understanding.
I am currently writing an application that receives location data every minute (or other specified amount of time) and thes send it to server.
The problem that I have noticed is:
When I use my application connected to power source it works perfectly - sends updates with defined interval.
When I use it on battery it sends updates randomly.
For my application I use timer to specify interval of update. This timer runs in Background service. I request updates in timer and remove updates when I receive location.
Fragment of my code:
private class mainTask extends TimerTask
{
public void run()
{
toastHandler.sendEmptyMessage(0);
}
}
private final Handler toastHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
date = date.getInstance(); //used to set time of update.
if(!GPSupdating)
{
locationManager.requestLocationUpdates("gps", 0, 0, locationListenerGPS);
GPSupdating = true;
}
}
};
My location listener:
LocationListener locationListenerGPS = new LocationListener()
{
public void onLocationChanged(Location updatedLocation)
{
myGPSLocation = updatedLocation;
haveLocationGPS = true;
locationManager.removeUpdates(locationListenerGPS);
GPSupdating = false;
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
Do you have any idea why this is not working correctly?
It's not good solution - enable/disable listener on each minute.
Better to try following things:
1) Set minimal update time (in requestLocationUpdates ) to one minute and send data to server in update listener:
locationManager.requestLocationUpdates("gps", 60*1000, 0, locationListenerGPS);
If you need more accurate update intervals, than:
2) Start separate thread and enable GPS updates on it. Store last location in thread or service variable. Also start timer and on timer tick send location to the server.
Try using Criteria to manage the power. Set power requirement to POWER_LOW. You will loose some accuracy though.
LocationManager locationManager= (LocationManager) getSystemService(context);
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setPowerRequirement(Criteria.POWER_LOW);
provider = locationManager.getBestProvider(criteria, true);
You will not save energy by enabling and disabling GPS once per minute. Either choose a greater intervall (5 minute) or get the location evry second.
Then store the location in a lastValidLocation filed, start your own Timer, and once a minute read out lastValidLocation. and send to server if changed.
I am trying to get a periodic update on location at a fixed interval. Right now, I am testing with a 2 minute interval just to make sure things are working. Then I will push it to a much longer interval.
Here is the relevant code:
public final int LOCATION_TIMER_RATE=120000;
locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
Log.d("BLAH", "Recorded home location as: (" + location.getLatitude() + "," + location.getLongitude() + ")");
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, LOCATION_TIMER_RATE, 0, locationListener);
If I request a single update, as follows, I always get a response back within 20 seconds or so. But, after that, I still do not get my periodic updates:
locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, locationListener, null);
If you request a single update, do you need to reschedule your periodic updates?
If you request a single update, then yes, you'd have to reschedule it for future updates. As for the requesting period updates not being consistent, it says so in the documentation. The updates can take longer (or possibly even shorter) than the time period you select.
I'm new to Android and I'm having the following problem. I'm writing a sample application where I have an intent service that first checks all location providers to get the last known location. If none of the last known locations provides an accurate (or timely) enough location then the location manager's requestLocationUpdates method is called with a BroadcastReceiver intent. Each time the broadcast receiver's onReceive method is called it should check the location to see if it is accurate and/or timely enough. I also have a TimerTask in the intent service that eventually goes off and should check to see if an accurate and/or timely enough location update has been obtained. The problem I'm having is that I don't know how to get the location data obtained in the broadcast receiver back to the intent service. Seems like this should be an easy thing to do but I've been agonizing over this for days. The only way I can think to do it is to write the data to an SQLite db in the broadcast receiver and then read those records back in the intent service, but this seems unnecessarily complicated. Does anyone know what the right way is to get the data back to the intent service? Should I even be using a broadcast receiver for requestLocationUpdates? Is there an easier way to do this? Here is the code
public class GetLocationService extends IntentService {
public GetLocationService() {
super("something");
}
LocationManager locationManager;
long maxFixLateness;
float maxFixPosUncertainty;
boolean usableLocObtained;
Location bestLoc = null;
float bestLocScore = 0;
Intent locChangeI;
PendingIntent pLocChangeI;
#Override
final protected void onHandleIntent(Intent intent) {
maxFixLateness = 30000;
maxFixPosUncertainty = 30;
long curTime = System.currentTimeMillis();
LocationManager locationManager = (LocationManager) this
.getSystemService(Context.LOCATION_SERVICE);
// Check for a usable location fix
List<string> matchingProviders = locationManager.getAllProviders();
for (String provider : matchingProviders) {
Location location = locationManager.getLastKnownLocation(provider);
if (location != null) {
// ...some code to check if the location is accurate or timely
// enough
}
}
if (bestLoc == null) {
locChangeI = new Intent(this, HandleLocationUpdateReceiver.class);
pLocChangeI = PendingIntent.getBroadcast(this, 0, locChangeI,
PendingIntent.FLAG_UPDATE_CURRENT);
usableLocObtained = false;
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 0, 0, pLocChangeI);
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 0, 0, pLocChangeI);
// Call the timer that will periodically check to see if a usable
// location has been obtained.
new LocFixCheckTimer(60000, 30, 1000);
}
}
private class LocFixCheckTimer {
Timer timer;
long numChecks;
public LocFixCheckTimer(long initSearchTime, long maxRechecks,
long recheckFreq) {
numChecks = maxRechecks;
timer = new Timer();
// Wait 2 seconds before checking for a fix again
timer.schedule(new CheckLocTask(), initSearchTime, recheckFreq);
}
class CheckLocTask extends TimerTask {
public void run() {
if (numChecks > 0) {
if (usableLocObtained == true) {
// I want to use the location data obtained from the
// HandleLocationUpdateReceiver's onReceive method
// but I don't how to get that data here.
}
} else {
// Cancel the timer. We've timed-out on searching
// for a usable location fix
timer.cancel();
}
--numChecks;
}
}
}
}
Here is the broadcast receiver:
public class HandleLocationUpdateReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Location loc = (Location) intent.getExtras().get(LocationManager.KEY_LOCATION_CHANGED);
if (loc != null)
{
double lat = loc.getLatitude();
double lon = loc.getLongitude();
// Do some checking to see how accurate and timely the location is
// here and somehow get it back to the intent service.
}
}
}
Thanks for the help!
Use a listener for sending back data to your activity or service. It is provided in this link
I am using the location manager's requestLocationUpdates() method to receive an intent to my broadcast receiver periodically. The system is correctly firing the intent to my receiver, and I have been able to use it correctly. The only problem is that the GPS location provider only stays active for a few seconds after the initial location acquisition, and I need it to stay on a little longer so that the location estimates are more accurate.
My question is how to make the GPS location provider stay active for each periodic request that comes from the LocationManager requestLocationUpdates. Does anyone know how to do this?
Try something like this. I think it is the right approach
private void createGpsListner()
{
gpsListener = new LocationListener(){
public void onLocationChanged(Location location)
{
curLocation = location;
// check if locations has accuracy data
if(curLocation.hasAccuracy())
{
// Accuracy is in rage of 20 meters, stop listening we have a fix
if(curLocation.getAccuracy() < 20)
{
stopGpsListner();
}
}
}
public void onProviderDisabled(String provider){}
public void onProviderEnabled(String provider){}
public void onStatusChanged(String provider, int status, Bundle extras){}
};
}
private void startGpsListener()
{
if(myLocationManager != null)
// hit location update in intervals of 5sec and after 10meters offset
myLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 10, gpsListener);
}
private void stopGpsListner()
{
if(myLocationManager != null)
myLocationManager.removeUpdates(gpsListener);
}
if you keep your LocationListener active, it should continue to receive updates to onLocationChanged() if the fix accuracy narrows. and indeed location.getAccuracy() will tell you the current accuracy
maybe set minTime and minDistance both to 0 to receive updates with greater frequency? will use more battery, but is more preise.
There is a example about get GPS location with timeout.
http://sikazi.blogspot.com/2010/09/android-gps-timeout.html#more
To get GPS location periodically, get the location from onLocationChanged method of locationListener and in onResume method specify the timing in milliseconds for getting periodic updates
onResume
location_manager.requestLocationUpdates(provider, 1000, 1, MainActivity.this);