I want to send some data along with coordinates to a remote server each 10 seconds. I thought, that the best match would be the
public void onCreate( Bundle savedInstanceState ) {
//snip
locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 10000, 0, new SendingLocationListener() );
}
in the listener I have the following code:
public void onLocationChanged( Location location ) {
if( null == location ) return;
TrackerNotifierTask task = new TrackerNotifierTask();
task.execute( location );
}
the TrackerNotifierTask uses the httpclient in it's doInBackground() method, so it's pretty simple.
Now, if I start the activity, I can see that the onLocationChanged() gets executed and the data hits the remote server successfully. But only once! No matter what I do later, changing coords or anything, the task does not get called.
Is this the right way of implementing such thing in android or shall I resort to some background-service?
the link from Shrikant gave me some hints on class-structure of the LocationListener implementation.
The class must not necessarily be defined as an inner anonymous class. I defined it as inner, but named one and it also worked.
The trick is, that the listener instance must be declared as a field:
private LocationListener listener;
#Override
public void onCreate( Bundle savedInstanceState ) {
//snip
locationManager = (LocationManager)this.getSystemService( Context.LOCATION_SERVICE );
listener = new MyLocationListener( SomeActivity.this );
locationManager.requestLocationUpdates( provider, 1000, 0, listener );
}
Otherwise it will be garbage-collected after the 1st run, if defined like this:
locationManager.requestLocationUpdates( provider, 1000, 0, new MyLocationListener() );
That was one half of the solution. The other part - about minTime - remains unresolved. Maybe it has something to do with emulator... I'll post the missing part as soon as I find the way.
UPDATE:
Seems like, that on a real device the minInterval seems to cause the listener to fire, no matter if the coords changed or not
Please see this.
It works as expected when LocationListener is implemented as an anonymous class.
I'v a similar problem,
when I use
private LocationListener mLocationListener1 = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
}
}
in my class,
onLocationChanged is only invoked once,
but after I add "final" to
private final LocationListener mLocationListener1 = new LocationListener() {
The problem is solved. (in my case, used by forground service)
It seems like
if the variable is not defined with final keyword,
after it was called once ,
it would be garbage collected and will not be called again...
Related
OLD QUESTION:
I'm trying to get my device's location coordinates and I've followed all the steps that I've found in multiple areas while researching. I've set up a LocationManager and used the requestLocationUpdates function that is tied to a LocationListener. However, the LocationListener does not respond. I've tried debugging as well as walking around outside in order for the onChangedLocation function to execute but nothing happens. In debugging the requestLocationUpdates function for my LocationManager is executed but the LocationListener is never executed.
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
textView = (TextView) findViewById(R.id.textView);
textView2 = (TextView) findViewById(R.id.textView2);
locationListener = new myLocationListener();
textView.setText("Longitude", TextView.BufferType.NORMAL);
textView2.setText("Latitude", TextView.BufferType.NORMAL);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 3000, 0, locationListener);
requestLocationUpdates
Above is the use of the requestLocationUpdates function.
private class myLocationListener implements LocationListener {
#Override
public void onLocationChanged(Location location) {
//Log.e("Latitude: ", "" + location.getLatitude());
//Log.e("Longitude: ", "" + location.getLongitude());
if(location != null)
{
textView.setText(Double.toString(location.getLongitude()), TextView.BufferType.NORMAL);
textView2.setText(Double.toString(location.getLatitude()), TextView.BufferType.NORMAL);
}
else
{
textView.setText("No Location", TextView.BufferType.NORMAL);
textView2.setText("No Location", TextView.BufferType.NORMAL);
}
Toast.makeText(getApplicationContext(),"onLocationChanged Success",Toast.LENGTH_LONG).show();
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
}
myLocationListener
This is myLocationListener that implements LocationListener. I've added a little bit of extra code for testing purposes. The toast would never pop up so it appears as though this code is never executed. If anyone could help me out with this I would really appreciate it.
Thank you!
NEW QUESTION:
After continuing on developing in this page while waiting for a response I noticed that it takes about a minute for the location services to actually begin working. So, now my question is: how do I overcome the obstacle of a user having to wait to use the app? I've seen apps that use location based content and it does not take that long. I know that there is the getLastKnownLocation function but what if a user travels 50 miles before opening the app again? Any help on this would be appreciated. Thank you!
Each device which makes location request for gps, has to wait until gps hardware become warm. The wait time changes by device and where you stay. If you are inside a building, this time could take 1 minute or more.
To avoid wait, you can use getLastKnownLocation method, if returns a cached location, check location's date via getTime method. Determine yourself, is it old location by your scenario ?
if it's too old location, you have to make location request and wait.
I am trying the 'LocationUpdates' sample from http://developer.android.com/training/location/receive-location-updates.html . This application gets and prints location notifications.
I am trying to change the interval of the location updates according to my latest location.
So - I had added mLocationRequest.setInterval() into onLocationChanged
The result is very wrong. My application is bombarded with many location updates (few a second!!!!)
My only change to the sample is this:
private int x=0;
#Override
public void onLocationChanged(Location location) {
// Report to the UI that the location was updated
mConnectionStatus.setText(R.string.location_updated);
// In the UI, set the latitude and longitude to the value received
mLatLng.setText(String.valueOf(x++));
mLocationRequest.setInterval(1000); // Change 1
mLocationClient.requestLocationUpdates(mLocationRequest, this); // Change 2
}
How can I change the interval inside onLocationChanged ?
I think that the problem is that requestLocationUpdates resets the last request, and then immediately sends another notification. so a loop is created. (faster than the fastest interval). so I need a reliable way to change the interval of a 'live' LocationRequest
You are not supposed to call mLocationClient.requestLocationUpdates(mLocationRequest, this); inside onLocationChanged(Location location)
since you are registering the listener again, and you will get the first call immediately.
so what i would do would be:
dont call mLocationClient.requestLocationUpdates(mLocationRequest, this); and see if anyways mLocationRequest.setInterval(1000); is taking effect
if this doesnt work, try to unregister the listener, and then use a trick to wait before registering it again with the new settings, something like:
Handler h = new Handler();
#Override
public void onLocationChanged(Location location) {
//... all your code
mLocationRequest.setInterval(1000);
mLocationClient.removeLocationUpdates(LocationListener listener)
h.postDelayed (new Runnable(){
public void run(){
mLocationClient.requestLocationUpdates(mLocationRequest, YOUROUTTERCLASS.this);
}
}, 1000);
}
So during one second there is not registered listener, so you wont get any updated, and after that, the listener is registerered with that interval.
Try using mLocationRequest.setFastestInterval(long millis)
As mentioned in developer.android.com :
This allows your application to passively acquire locations at a rate faster than it actively acquires locations, saving power. Unlike setInterval(long), this parameter is exact. Your application will never receive updates faster than this value.
Try to use :
mLocationRequest.requestLocationUpdates("gps", 1000, 0, this);
However I don't agree to do a requestLocationUpdates in onLocationChanged event; In my opinion should be setted outside onLocationChanged Event...
I am trying to get my location in a map using the setMyLocationEnabled() method. There is no problem with this method, I have also used setMyLocationButtonEnabled() and everything is good.
But when I click on the button in the map, I don't get the "blue dot" that indicates my location.
Can you tell me what the problem could be?
The setMyLocationEnable won't work alone. you have to put requestLocationUpdates in the onResume.
#Override
public void onResume() {
super.onResume();
if (isGPSEnabled) {
locMgr.requestLocationUpdates(LocationManager.GPS_PROVIDER, time, distance, this);
}
if (isNetworkEnabled) {
locMgr.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, time, distance, this);
}
map.setLocationSource(this);
}
First, you should either declare an anonymous inner class, that implements Google.OnMyLocationChangeListener, or you could just implement it in your main class. Let's say the instance of your map is called map. You will have to set the listener, like this: map.setOnMyLocationChangeListener(this). Then, you will have to do something like this:
#Override
public void onMyLocationChange(Location location) //inherited from the interface you implemented
{
//do your thing, the variable "location" holds everything you need
}
I have been working for 2 days looking for this bug. I have searched stackoverflow and Android documentation with no luck.
My onLocationChanged code has a counter in it that counts how many times it has been called and if I back arrow out of the activity screen on the phone and return, the counter will go up by 2 for each update. If I back arrowing out and update the GPS, the counter records that onLocationChanged is still getting called even though the screen is in the background and onPause has been called. If I go in and out of the activity with the backarrow, I can get more than two updates per GPS input send depending on how many times the activity screen is entered.
All the GPS code works but these multiple instances can't be good and they mess up other things I am trying to do, like distance traveled between two updates.
Here is what I think is the relevant parts of my code. Obviously I left out the main part but the point is that after returning to this screen after back-arrowing out then a single send of a GPS data point increments the n variable by more than one depending on how many times I have returned to the screen.
I must be doing something obvious but I can't find it.
public class Data extends Activity {
protected LocationListener ll;
protected LocationManager lm;
static int n = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.data);
LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
LocationListener ll = new mylocationlistener();
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, ll);
}
class mylocationlistener implements LocationListener{
#Override
public void onLocationChanged(Location location) {
if (location != null){
n = n + 1;
textData.setText("\n" + n);
}
}
and
#Override
protected void onPause() {
if(lm != null) {
lm.removeUpdates(ll);
}
ll = null;
lm = null;
super.onPause();
}
The only clue I have is that if I take the lm.removeUpdates(ll) out of the if(lm != null) then the code crashes which makes me think that lm must be null and that lm.removeUpdates(ll) must not be correct but it matches the all the examples I could find as well as the Android documentation as far as I can tell.
Please help.
LocationListener ll = new mylocationlistener();
This LocationListener is local to your method onCreate().So is your LocationManager lm.So when you are removing updates its not working with the manager and listener that you declared as the class variable.
Just write as
lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
ll = new mylocationlistener(); in your onCreate().
My app checks at a specific time whether a user is at a given location. I use the alarm manager to start a service that makes this call:
locationManager.requestLocationUpdates(bestProvider, 0, 0, listener);
And also checks:
locationManager.getLastKnownLocation(bestProvider);
But I'm having problems when running on a real device. For one thing, getLastKnownLocation is most likely the last place the GPS was on, which could be anywhere (i.e., it could be miles from the user's current location). So I'll just wait for requestLocationUpdates callbacks, and if they aren't there within two minutes, remove the listener and give up, right?
Wrong, because if the user's location is already stable (i.e., they've used GPS recently and haven't moved) then my listener will never be called because the location doesn't change. But the GPS will run until my listener is removed, draining the battery...
What is the right way to get the current location without mistaking an old location for the current location? I don't mind waiting a few minutes.
EDIT: It's possible that I'm wrong about the listener not being called, it may just take a little longer than I thought... Hard to say. I'd appreciate a definitive answer still.
The code may be something like that:
public class MyLocation {
Timer timer1;
LocationManager lm;
public boolean getLocation(Context context)
{
lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
timer1=new Timer();
timer1.schedule(new GetLastLocation(), 20000);
return true;
}
LocationListener locationListenerGps = new LocationListener() {
public void onLocationChanged(Location location) {
timer1.cancel();
lm.removeUpdates(this);
//use location as it is the latest value
}
public void onProviderDisabled(String provider) {}
public void onProviderEnabled(String provider) {}
public void onStatusChanged(String provider, int status, Bundle extras) {}
};
class GetLastLocation extends TimerTask {
#Override
public void run() {
lm.removeUpdates(locationListenerGps);
Location location=lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
//use location as we have not received the new value from listener
}
}
}
We start the listener and wait for update for some time (20 seconds in my example). If we receive update during this time we use it. If we don't receive an update during this time we use getLastKnownLocation value and stop the listener.
You can see my complete code here What is the simplest and most robust way to get the user's current location on Android?
EDIT (by asker): This is most of the answer, but my final solution uses a Handler instead of a Timer.
If the user's location is already stable, then getLastKnownLocation will return the current location. I'd call getLastKnownLocation first, look at the timestamp (compare Location.getElapsedRealTimeNanos() with SystemClock.elapsedRealTimeNanos()) then register a listener if the fix is too old.