I'm stuck trying to refresh the user's location.
In my app, I start the map marking user's current location, but locationManager.getLastKnownLocation() is returning a different location
because it uses a cache location.
How can I compare the last known location with the current location so I can mark the correct position on the map in the callback OnMapReady?
Every example I found in StackOverflow is using LocationListener.onLocationChanged() method, but I need to refresh the location (if needed) on activity launch.
Code:
private static final String TAG_MAP_LOAD_FAILED = "FAIL LOADING MAP STYLE";
private static final String TAG_MAP_PARSING_FAILED = "FAIL PARSING MAP STYLE";
private GoogleMap mMap;
private LatLng mMyCoordinates;
private LocationManager mLocationManager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLocationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
try{
boolean success = googleMap.setMapStyle(MapStyleOptions.loadRawResourceStyle(getContext(), R.raw.style_mapjson));
if(!success){
Log.e(TAG_MAP_PARSING_FAILED, "Failed parsing JSON Style");
}
}catch (Resources.NotFoundException ex){
Log.e(TAG_MAP_LOAD_FAILED, "Can't find style. Error:", ex);
}
mMap.setIndoorEnabled(false);
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(mMyCoordinates);
markerOptions.title("Marker in my location");
mMap.addMarker(markerOptions);
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(mMyCoordinates, 15);
mMap.moveCamera(cameraUpdate);
mMap.getUiSettings().setRotateGesturesEnabled(false);
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
OBS: I cleaned up the code because it was getting full of unsuccessful attempts. Just showing how it is structured.
Should I use FusedLocation instead?
The last known location has a timestamp associated with it, which can be quite some time in the past. Just do an age comparison with the last known location's timestamp with the max age you'd allow, and request an update when needed. Here is a quick and dirty example:
private static long MAX_TIME = 60 * 60 * 1000; //Update if location is older than one hour
#Override
public void onResume() {
super.onResume();
Location location = mLocationManager.getLastKnownLocation(YOUR_PROVIDER_HERE); //GPS or Network
boolean shouldUpdateLocation = false;
if (location != null) {
long elapsedTime = System.currentTimeMillis() - location.getTime();
if (elapsedTime >= MAX_TIME) {
shouldUpdateLocation = true;
}
}
else {
shouldUpdateLocation = true;
}
if (shouldUpdateLocation) {
//TODO: Request location update here.
}
}
You don't want to be requesting location updates every time the activity is brought up, so set up a reasonable MAX_TIME for this.
Related
Hi recently I have been working with the application that requires to track the distance the person traveled while he is walking. I am using the location manager for getting the person coordinates ( lang and lat).
locationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
location.getLatitude();
location.getLongitude();
}
#Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onProviderDisabled(String s) {
}
};
How can I use the method distanceBetween() to get the actual distance traveled?
I am confused how to distinguish starting position and end position, as location manager gives you the current position and keeps giving back new position every 5s ( thats what I configured to be on requestLocationUpdates() )
Any help would be appreciated, thanks
I am confused how to distinguish starting position and end position, as location manager gives you the current position and keeps giving back new position every 5s
You already have the code available to get a new location, so you need to save the old Location and calculate distance to new location during every location update.
Location oldLoc, newLoc;
locationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
if (oldLoc!=null) {
if (newLoc == null) {
newLoc = location;
// get distance
return;
}
// else, both not null
oldLoc = newLoc;
newLoc = location;
// get distance
} else { oldLoc = location; }
}
I have involved with location problems. I am getting my first time location and if i tried for next location, it is giving me Last location all time. I changed my location may times but all time, I am getting Last latitude and longitude. I think, GPS don't refresh.
If i restarted to my phone and try again. it display to correct location and if i tried again, it is displaying me Last location.
I am sharing my source code
#Override
protected void onResume() {
super.onResume();
if(mMap!= null)
mMap.clear();
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
mFragment = (SupportMapFragment) this.getSupportFragmentManager().findFragmentById(R.id.map);
mMap = mFragment.getMap();
//if(loc != null)
//loc.reset();
loc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if(loc != null) {
LatLng geo = HelperUtil.getLatLng(loc);
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(geo, 18));
mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
}
setListener();
}
private void setListener(){
if(locationListener != null){
clearListener();
}
Toast toast = Toast.makeText(this, this.getResources().getString(R.string.maps_loading), Toast.LENGTH_LONG);
toast.show();
locationListener = new CustomLocationListener();
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
Handler handler=new Handler();
handler.postDelayed(new TimeoutTask(locationListener), 15*1000);
}
private void clearListener(){
if(locationListener != null){
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
locationManager.removeUpdates(locationListener);
locationListener = null;
}
}
public class CustomLocationListener implements LocationListener {
private boolean isCompleted = false;
public CustomLocationListener() {}
#Override
public void onLocationChanged(Location location) {
isCompleted=true;
// Called when a new location is found by the network location provider.
if(isBetterLocation(location, loc)){
gotLocation(location);
}
clearListener();
setUserPoint();
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
#Override
public void onProviderEnabled(String provider) {}
#Override
public void onProviderDisabled(String provider) {}
public boolean isCompleted() {
return isCompleted;
}
}
public class TimeoutTask implements Runnable {
private CustomLocationListener listener;
public TimeoutTask(CustomLocationListener listener) {
this.listener=listener;
}
#Override
public void run() {
// TODO Auto-generated method stub
if (listener == null || listener.isCompleted()) {
Log.e("provider", "completed");
System.out.println("Lat in completed= "+loc.getLatitude());
System.out.println("Long in completed = "+loc.getLongitude());
}
else {
Log.e("provider", "timeout");
clearListener();
setUserPoint();
}
}
}
protected boolean isBetterLocation(Location location, Location currentBestLocation) {
if (currentBestLocation == null) {
// A new location is always better than no location
return true;
}
// Check whether the new location fix is newer or older
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
boolean isNewer = timeDelta > 0;
// If it's been more than two minutes since the current location, use the new location
// because the user has likely moved
if (isSignificantlyNewer) {
return true;
// If the new location is more than two minutes older, it must be worse
} else if (isSignificantlyOlder) {
return false;
}
// Check whether the new location fix is more or less accurate
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// Check if the old and new location are from the same provider
boolean isFromSameProvider = isSameProvider(location.getProvider(),
currentBestLocation.getProvider());
// Determine location quality using a combination of timeliness and accuracy
if (isMoreAccurate) {
return true;
} else if (isNewer && !isLessAccurate) {
return true;
} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
return true;
}
return false;
}
private void gotLocation(Location location){
loc = location;
}
Please expert help me. I also noted that sometime i am not able to get location and it say timeout. Your time will be very helpful for me.
you are using network location which doesn't provide the correct location rather than using network location you should use the GPS location for current and accurate location.
getLastKnowLocation() method doesn't provide the correct , current location for this you can refer this link.
rather than using network location use GPS location and you can find the good example of GPS location from the given link.
http://www.androidhive.info/2012/07/android-gps-location-manager-tutorial/
For your concern .. make use of LocationClient instead of LocationManager class...
Try like this ..
LocationClient locationClient; // initialize
Location src; // It will store your location
then in your onCreate method ..
locationClient = new LocationClient(this, this, this);
locationClient.connect(); // this will call OnConnected method of location client
#Override
public void onConnectionFailed(ConnectionResult arg0) {
// TODO Auto-generated method stub
}
#Override
public void onConnected(Bundle arg0) {
src = locationClient.getLastLocation();
System.out.println("======================location 1==" + src);
// This is your location update .. it will update each time your location is //changed
LocationRequest lrequest = new LocationRequest();
lrequest.setInterval(0);
lrequest.setSmallestDisplacement(0);
locationClient.requestLocationUpdates(lrequest, new LocationListener() {
#Override
public void onLocationChanged(Location arg0) {
Toast.makeText(getApplicationContext(),
"Location is 12" + arg0.getLatitude(),
Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void onDisconnected() {
// TODO Auto-generated method stub
}
OR
If you are using Google Map and need to update location of device on Google map then you may make use of Google Map methods as it will provide you current location on device rather than Last location of device ..
Try like this ..
GoogleMap myMap;
Now on Oncreate get your map reference
myMap = ((SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map)).getMap();
myMap.setMyLocationEnabled(true);
Now when you need to get location then try like this ..
Location location = new Location();
location = myMap.getMyLocation;
That's it .. you are good to go!
First of all make sure you are including the following two lines of code in the manifest:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
Then I would use something similar to the below to get location updates:
public class MainActivity extends FragmentActivity implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener,
LocationListener {
...
// Global variables
...
LocationClient mLocationClient;
boolean mUpdatesRequested;
...
#Override
protected void onCreate(Bundle savedInstanceState) {
...
// Open the shared preferences
mPrefs = getSharedPreferences("SharedPreferences",
Context.MODE_PRIVATE);
// Get a SharedPreferences editor
mEditor = mPrefs.edit();
/*
* Create a new location client, using the enclosing class to
* handle callbacks.
*/
mLocationClient = new LocationClient(this, this, this);
// Start with updates turned off
mUpdatesRequested = false;
...
}
...
#Override
protected void onPause() {
// Save the current setting for updates
mEditor.putBoolean("KEY_UPDATES_ON", mUpdatesRequested);
mEditor.commit();
super.onPause();
}
...
#Override
protected void onStart() {
...
mLocationClient.connect();
}
...
#Override
protected void onResume() {
/*
* Get any previous setting for location updates
* Gets "false" if an error occurs
*/
if (mPrefs.contains("KEY_UPDATES_ON")) {
mUpdatesRequested =
mPrefs.getBoolean("KEY_UPDATES_ON", false);
// Otherwise, turn off location updates
} else {
mEditor.putBoolean("KEY_UPDATES_ON", false);
mEditor.commit();
}
}
...
/*
* Called by Location Services when the request to connect the
* client finishes successfully. At this point, you can
* request the current location or start periodic updates
*/
#Override
public void onConnected(Bundle dataBundle) {
// Display the connection status
Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show();
// If already requested, start periodic updates
if (mUpdatesRequested) {
mLocationClient.requestLocationUpdates(mLocationRequest, this);
}
}
}
I would recommend you take a look at this tutorial.
Hope it helps you :)
Although the best option is to switch to new Location API based on Google Play Services (http://developer.android.com/training/location/index.html), here I am trying to explain what is wrong.
You are calling the setListener() method only once in onResume(). So the listener starts listening. But on any location change you are clearing the listener. As a result you'll get a last known location at first and then you'll get maximum one location update. After that as the listener is set as null, you'll not get any update. So you can fix it simply by modifying the TimeoutTask.
public class TimeoutTask implements Runnable {
private CustomLocationListener listener;
public TimeoutTask(CustomLocationListener listener) {
this.listener = listener;
}
#Override
public void run() {
// TODO Auto-generated method stub
if (listener == null || listener.isCompleted()) {
Log.e("provider", "completed");
System.out.println("Lat in completed= " + loc.getLatitude());
System.out.println("Long in completed = " + loc.getLongitude());
} else {
Log.e("provider", "timeout");
clearListener();
setUserPoint();
}
// setting the listener again
setListener();
}
}
I'm trying to use the GPS for my android application. In particular I use the coordinates received from the GPS (or alternatively from the 3g connection) to display the user's location on a map. But the user can use the app even when the GPS is off.
My question is: how do I automatically display the user's location after the activation of GPS (or 3g connection) when the application is already running?
Thanks
If you did not already call LocationManager.requestLocationUpdates(), you can listen for the PROVIDERS_CHANGED_ACTION Broadcast and start requesting location updates/displaying the user location accordingly.
If you already are requesting location updates, you can override your LocationListener's onProviderDisabled()/onProviderEnabled() methods to be notified when the availability of the provider changes.
Yes of course. In particular, when the application is running but WiFi or GPS are disabled, bestProvider() return however "network". And in this case, when i activate gps or wifi, the app doesn't recognize them. Also when the application is running and WiFi is on, when i activate GPS, the app doesn't identify it.
public class MainActivity extends FragmentActivity implements OnMapClickListener {
final int RQS_GooglePlayServices = 1;
private GoogleMap map;
private TextView tvLocInfo;
private FollowMeLocationSource followMeLocationSource;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvLocInfo = (TextView)findViewById(R.id.locinfo);
followMeLocationSource = new FollowMeLocationSource();
/* We query for the best Location Provider everytime this fragment is displayed
* just in case a better provider might have become available since we last displayed it */
followMeLocationSource.getBestAvailableProvider();
// Get a reference to the map/GoogleMap object
setUpMapIfNeeded();
map.setOnMapClickListener(this);
// TESTMARKER map.addMarker(new MarkerOptions()
// TESTMARKER map.addMarker(new MarkerOptions().position(new LatLng(41.934977, 12.488708))
// TESTMARKER .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)));
}
#Override
public void onResume() {
super.onResume();
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
if (resultCode == ConnectionResult.SUCCESS){
Toast.makeText(getApplicationContext(),
"isGooglePlayServicesAvailable SUCCESS",
Toast.LENGTH_LONG).show();
}else{
GooglePlayServicesUtil.getErrorDialog(resultCode, this, RQS_GooglePlayServices);
}
/* We query for the best Location Provider everytime this fragment is displayed
* just in case a better provider might have become available since we last displayed it */
followMeLocationSource.getBestAvailableProvider();
// Get a reference to the map/GoogleMap object
setUpMapIfNeeded();
//Enable the my-location layer (this causes our LocationSource to be automatically activated.)
map.setMyLocationEnabled(true);
}
#Override
public void onPause() {
super.onPause();
/* Disable the my-location layer (this causes our LocationSource to be automatically deactivated.) */
map.setMyLocationEnabled(false);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the map.
if (map == null) {
FragmentManager myFragmentManager = getSupportFragmentManager();
SupportMapFragment mySupportMapFragment
= (SupportMapFragment)myFragmentManager.findFragmentById(R.id.map);
map = mySupportMapFragment.getMap();
// Check if we were successful in obtaining the map.
if (map != null) {
Location location = followMeLocationSource.getLastKnownLocation();
LatLng latlng= new LatLng(location.getLatitude(), location.getLongitude());
map.moveCamera(CameraUpdateFactory.newLatLng(latlng));
// The Map is verified. It is now safe to manipulate the map.
// Replace the (default) location source of the my-location layer with our custom LocationSource
map.setLocationSource(followMeLocationSource);
map.setMyLocationEnabled(true);
map.moveCamera(CameraUpdateFactory.zoomTo(15f));
}
}
}
#Override
public void onMapClick(LatLng point) {
tvLocInfo.setText(point.toString());
map.animateCamera(CameraUpdateFactory.newLatLng(point));
}
/* Our custom LocationSource.
* We register this class to receive location updates from the Location Manager
* and for that reason we need to also implement the LocationListener interface. */
private class FollowMeLocationSource implements LocationSource, LocationListener {
private final Criteria myCriteria = new Criteria();
private String bestAvailableProvider;
LocationManager myLocationManager = null;
OnLocationChangedListener myLocationListener = null;
/* Updates are restricted to one every 10 seconds, and only when
* movement of more than 10 meters has been detected.*/
private final int minTime = 10000; // minimum time interval between location updates, in milliseconds
private final int minDistance = 10; // minimum distance between location updates, in meters
private FollowMeLocationSource() {
// Get reference to Location Manager
myLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
// Specify Location Provider criteria
myCriteria.setAccuracy(Criteria.ACCURACY_FINE);
myCriteria.setPowerRequirement(Criteria.POWER_LOW);
myCriteria.setBearingRequired(true);
}
private void getBestAvailableProvider() {
/* The prefered way of specifying the location provider (e.g. GPS, NETWORK) to use
* is to ask the Location Manager for the one that best satisfies our criteria.
* By passing the 'true' boolean we ask for the best available (enabled) provider. */
bestAvailableProvider = myLocationManager.getBestProvider(myCriteria, true);
Log.i("Best Provider:", bestAvailableProvider);
}
private Location getLastKnownLocation() {
Location lastKnownLocation = myLocationManager.getLastKnownLocation(bestAvailableProvider);
Double lat = lastKnownLocation.getLatitude();
return lastKnownLocation;
}
#Override
public void onLocationChanged(Location location) {
/* Push location updates to the registered listener..
* (this ensures that my-location layer will set the blue dot at the new/received location) */
Log.i("EntradentroOnLocationChanged", "Entrato");
if (myLocationListener != null) {
myLocationListener.onLocationChanged(location);
double lat = location.getLatitude();
double lon = location.getLongitude();
tvLocInfo.setText(
"lat: " + lat + "\n" +
"lon: " + lon);
}
// ..and Animate camera to center on that location
//LatLng latlng= new LatLng(location.getLatitude(), location.getLongitude());
//map.animateCamera(CameraUpdateFactory.newLatLng(latlng));
}
#Override
public void onProviderDisabled(String provider) {
getBestAvailableProvider();
}
#Override
public void onProviderEnabled(String provider) {
getBestAvailableProvider();
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
/* Activates this provider. This provider will notify the supplied listener
* periodically, until you call deactivate(). */
#Override
public void activate(OnLocationChangedListener listener) {
// We need to keep a reference to my-location layer's listener so we can push forward
// location updates to it when we receive them from Location Manager.
myLocationListener = listener;
// Request location updates from Location Manager
if (bestAvailableProvider != null) {
myLocationManager.requestLocationUpdates(bestAvailableProvider, minTime, minDistance, this);
} else {
// TODO (Display a message/dialog) No Location Providers currently available.
}
}
/* Deactivates this provider.
* This method is automatically invoked by disabling my-location layer. */
#Override
public void deactivate() {
// Remove location updates from Location Manager
myLocationManager.removeUpdates(this);
myLocationListener = null;
}
}
}
When my map activity is called I make a call in the onCreate to addUserMapPoint. This function contains two instances where I try to get the location information using myOverlay.getMyLocation. On the initial load of this activity the result of the first attempt returns a null GeoPoint and after the main UI thread completes the second attempt located in the listener thread of myOverlay.runOnFirstFix(new Runnable()… is call after a second and does contain a GeoPoint that does contain a lat and lon. The call inside this listener function does appear to put the dot on the map and the line mapController.animateTo(gp) does move the map to my location. My app has a refresh button that when clicked fires off this activity again. I need the lat and lon in order to fetch location data from another service. After the refresh, the second time through the map activity code I was expecting the first call to myOverlay.getMyLocation() would now be able to get the GeoPoint, but it is still null.
If I’m not able to get the GeoPoint by this first call to myOverlay.getMyLocation then how can I pass the lat and lon value from the second call found in the myOverlay.runOnFirstFix(new Runnable()… thread. You will notice that I have been trying to add the lat and lon to MyApp which is helper bean class but the lat and lon in this class is null even after the refresh. If I manually set a lat and lon manually in the addUserMapPoint function the first time the activity is accessed these values are retained. I’m guessing that this is because it is being set on the main UI thread.
public class MapActivity extends com.google.android.maps.MapActivity {
private MapView mapView = null;
private MapController mapController = null;
private MyLocationOverlay myOverlay = null;
public static MyApp app;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
app = (MyApp) getApplicationContext();
mapView = (MapView) findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
mapController = mapView.getController();
List<Overlay> mapOverlays = mapView.getOverlays();
mapOverlays.clear();
addUserMapPoint(mapView);
if (!app.isLocServOff()) {
//map other points – service call to get items from our service near lat and lon
addOtherMapPoints(mapOverlays);
} else {
Toast.makeText(app.getApplicationContext(),"Current location could not be found.",Toast.LENGTH_LONG).show();
}
}
private void addUserMapPoint(MapView mapView){
myOverlay = new MyLocationOverlay(app.getApplicationContext(), mapView);
myOverlay.disableCompass();
myOverlay.enableMyLocation();
if(app.getMyLat()==null||app.getMyLon()==null){
GeoPoint gp = myOverlay.getMyLocation();
if(gp!=null){
app.setMyLat(Helper.latLon1E6Calc(gp.getLatitudeE6()));
app.setMyLon(Helper.latLon1E6Calc(gp.getLongitudeE6()));
app.setLocServOff(false);
}else{
app.setLocServOff(true);
}
}
myOverlay.runOnFirstFix(new Runnable() {
public void run() {
GeoPoint gp = myOverlay.getMyLocation();
if(gp!=null){
app.setMyLat(Helper.latLon1E6Calc(gp.getLatitudeE6()));
app.setMyLon(Helper.latLon1E6Calc(gp.getLongitudeE6()));
app.setLocServOff(false);
mapController.animateTo(gp);
}else{
app.setLocServOff(true);
}
}
});
mapView.getOverlays().add(myOverlay);
}
}
Your help is being requested for the following question.
How can I get a GeoPoint that contains a lat and lon in the main UI thread or how can I pass these values from GeoPoint I am able to get from the myOverlay.runOnFirstFix(new Runnable()… thread?
If you are going to suggest that I use Handler or runOnUiThread please provide code example that passes the lat and lon back to something that can be used by the main UI thread/map view. I have tried things like the following code that did not produce the desired outcome. I was able to get the toast message to show up, but was not able to get the lat and lon passed in a way I could use.
final Handler handler = new Handler();
myOverlay.runOnFirstFix(new Runnable() {
#Override public void run() {
handler.post(new Runnable() {
#Override public void run() {
GeoPoint gp = myOverlay.getMyLocation();
if(gp!=null){
app.setMyLat(Helper.latLon1E6Calc(gp.getLatitudeE6()));
app.setMyLon(Helper.latLon1E6Calc(gp.getLongitudeE6()));
app.setLocServOff(false);
mapController.animateTo(gp);
}else{
app.setLocServOff(true);
}
//Toast.makeText(getApplicationContext(),"wowoowowowoowoowowow",Toast.LENGTH_LONG).show();
}
});
}
});
I've also used code like the following to get the lat and lon and it works, but because the current location would sometimes be a different lat and lon than whas was being returned becuase for example I could not get a gps signal but yet an old value was returned. I added checks to see if the lat/lon data was older than 2 minutes, but I still could not match up the most recent lat and lon with that that is returned by myOverlay.getMyLocation.
LocationManager locMgr = (LocationManager)appcontext.getSystemService(Context.LOCATION_SERVICE);
MyLocationListener locLstnr = new MyLocationListener();
//fetch current location for current location
locMgr.requestSingleUpdate(LocationManager.GPS_PROVIDER, locLstnr, appcontext.getMainLooper());
Bellow you can find some examples on how to get the current location in the UI thread, but first of all, some background information.
GPS may take some time (15 seconds to 1 minute) to get the first fix after the request for new location is made. This is the reason you your first attempt to get it from myOverlay fails, and only after the first fix you can get the value.
During this blackout period you can use getLastKnownLocation() to get the last good known GPS location if you are in a hurry. If not availble it returns null
The code:
Last Known Location
LocationManager locMgr=(LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
Location loc = locMgr.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if(loc != null){
//we have a valid location. Check location date
}
Requesting a Single Location Update
LocationManager locMgr=(LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
locMgr.requestSingleUpdate(LocationManager.GPS_PROVIDER, locationListener, appcontext.getMainLooper);
Requesting a Continuous Location Update
LocationManager locMgr = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
//use 0 for minDistance and minDistance between updates if you need the maximum update frequency.
locMgr.requestLocationUpdates(LocationManager.GPS_PROVIDER, minDistance, minTime, locationListener);
Location Listener for Single and Continuous position update
This is the last piece of code, and is the place where you get the new fresh locations requested above.
When a new location that match your request critirea defined above is retrieved by GPS, this listener is immediately called, unless you device is busy doing something else that can't be interrupted (i.e. callback is on a paused thread or that hit a lock).
From within the onLocationChanged() you can set any class level filed as appropriate. If you registered the listener from the UI thread, then this will be running running on the UI.
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location fix) {
fix.setTime(fix.getTime() + timeZoneOffset); //Add Timezone offset if needed
//here you have a fresh new location in fix...
//You can set the value of any class level field from here
}
public void onProviderDisabled(String provider) {
}
public void onProviderEnabled(String provider) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
Regards.
handler.post(new Runnable() {
#Override public void run() {
GeoPoint gp = myOverlay.getMyLocation();
if(gp!=null){
app.setMyLat(Helper.latLon1E6Calc(gp.getLatitudeE6()));
app.setMyLon(Helper.latLon1E6Calc(gp.getLongitudeE6()));
app.setLocServOff(false);
// HERE WE HAVE VALID gp VALUE AND WE NEED TO SHARE IT
mapController.animateTo(gp);
}else{
app.setLocServOff(true);
}
}
});
I think that your app.set/get|MyLat/Lon not working because you call them from different threads. To fix it synchronize set and get methods for MyLat/Long. (create Object for synchronization and sync on it)
Or if you like your way with handler this should work:
final Handler handler = new Handler(); // BE SURE TO RUN THIS LINE ON UI THREAD
...
myOverlay.runOnFirstFix(new Runnable() {
#Override public void run() {
// THIS PART WORKS AS BEFORE
final GeoPoint gp = myOverlay.getMyLocation();
mapController.animateTo(gp);
...
// AND THIS RUNNABLE TO UPDATE MyLat/MyLong FROM UI THREAD
handler.post(new Runnable() {
#Override public void run() {
app.setMyLat(Helper.latLon1E6Calc(gp.getLatitudeE6()));
app.setMyLon(Helper.latLon1E6Calc(gp.getLongitudeE6()));
});
}
});
Some of the most important points you must take into account while seeking Device's location are:
Satellite GPS fix is not guaranteed to be received in adequate amount of time. E.g. the device is inside a building / not under open sky.
Make sure the satellite GPS listeners are not kept active for long. Keeping the listener ON will imply keeping the GPS radio on all the time making it the biggest battery drain reason.
In the below code example, the poll method in LinkedBlockingQueue doesn't return until either a specified time interval is over or a Location is queued in.
Use something like the below to get the current Location:
Location getCurrentLocation() {
long startmillis = 0;
LinkedBlockingQueue<Location> mQueue = new LinkedBlockingQueue<Location>();
try{
long millisSinceLastCollection = System.currentTimeMillis() - startmillis;
startmillis = System.currentTimeMillis();
mQueue.clear();
// Register for Satellite GPS listener as well as Network GPS listener.
registerGPSListeners();
// Wait for a maximum of one minutes for a fix
Location firstfix = mQueue.poll(1, TimeUnit.MINUTES);
if(firstfix != null && firstfix.getProvider().equals(LocationManager.GPS_PROVIDER)) {
return firstfix;
}
long elapsedmillis = System.currentTimeMillis() - startmillis;
long remainingmillis = ONE_MINUTE_IN_MS - elapsedmillis;
if (remainingmillis <= 0){
return firstfix;
}
Location secondfix = mQueue.poll(remainingmillis, TimeUnit.MILLISECONDS);
if(secondfix != null && secondfix.getProvider().equals(LocationManager.GPS_PROVIDER)) {
return secondfix;
}
/*
* In case we receive fix only from Network provider, return it.
*/
if(firstfix != null && firstfix.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
return firstfix;
}
} catch(Exception e){
Logger.e("GPS: Exception while listening for the current location", e);
} finally {
Logger.i("GPS: Unsubscribing from any existing GPS listeners");
unregisterGPSListeners();
}
}
// GPS issue fix edit.
private void registerGPSListeners() {
LocationManager locationManager = (LocationManager)AirWatchApp.getAppContext().getSystemService(Context.LOCATION_SERVICE);
if(locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER))
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 30000, 100, oneShotNetworkGPSLocationListener, MyAppApp.getAppContext().getMainLooper());
if(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 30000, 100, oneShotSatelliteGPSLocationListener, AirWatchApp.getAppContext().getMainLooper());
}
}
private void unregisterGPSListeners(){
final LocationManager locationManager = (LocationManager)MyApp.getAppContext().getSystemService(Context.LOCATION_SERVICE);
locationManager.removeUpdates(oneShotSatelliteGPSLocationListener);
locationManager.removeUpdates(oneShotNetworkGPSLocationListener);
}
//One shot location listener
protected LocationListener oneShotSatelliteGPSLocationListener = new LocationListener() {
public void onLocationChanged(Location location) {
try {
mQueue.put(location);
} catch (InterruptedException e) {
Logger.e("Exception in putting new Location to the queue", e);
}
Logger.d("GPS: Location received from Satellite GPS Provider");
unregisterGPSListeners();
}
public void onProviderDisabled(String provider) {}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
};
//One shot location listener
protected LocationListener oneShotNetworkGPSLocationListener = new LocationListener() {
public void onLocationChanged(Location location) {
try {
mQueue.put(location);
} catch (InterruptedException e) {
Logger.e("Exception in putting new Location to the queue", e);
}
Logger.d("GPS: Location received from Network GPS Provider");
// Stop Listener for one-shot location fix from Network GPS provider.
final LocationManager locationManager = (LocationManager)AirWatchApp.getAppContext().getSystemService(Context.LOCATION_SERVICE);
locationManager.removeUpdates(oneShotNetworkGPSLocationListener);
Logger.d("GPS: Unsubscribed the network location listener.");
}
public void onProviderDisabled(String provider) {}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
};
Android modifies the user interface and handles input events from one single user interface thread(main thread).
If the programmer does not use any concurrency constructs, all code of an Android application runs in this thread.
GPS is the best way to determine a user's location, but pinging a global positioning satellite too much will quickly drain a mobile device's battery, take long time to get user location and this method doesn't always work indoors. You are not getting your location in first attempt that's why you are getting null over there.
Android's Network Location Provider figures out a user's location based on cell tower and Wi-Fi signals. It not only uses less battery power than GPS, but it's also faster and it works whether the user is outside or inside.
I am giving my Working Code below that show progress dialog, listen for user's location & after getting location show user's location overlay on Google-map
I assume that you have give below permissions in your Menifest file
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
My main class
public class MyLocationOnMap extends MapActivity {
private MapView mapView;
private MyLocationOverlay itemizedoverlay;
private LocationManager locationManager;
private String provider;
private MyLocationListener locationListener;
MyBroadCastreceiver myBroadCastreceiver;
/**
* My current Location <i>longitude</i>.
*/
static int longitude;
/**
* My current Location <i>latitude</i>.
*/
static int latitude;
/**
*My progress indicator.
*/
ProgressDialog loadingDialog;
public static final String INTENT_FILTER_TAG="my location broadcast receiver";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_location_on_map);
loadingDialog = new ProgressDialog(this);
loadingDialog.setTitle("Hot Spots!");
loadingDialog.setMessage("Please wait ...");
loadingDialog.setIndeterminate(true);
loadingDialog.setCancelable(false);
loadingDialog.show();
// Configure the Map
mapView = (MapView) findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
mapView.setStreetView(true);
/**
* Get your location manager and Location Listener...
*/
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationListener=new MyLocationListener();
myBroadCastreceiver = new MyBroadCastreceiver();
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Log.i("GPS_Enabled", "GPS enable! listening for gps location.");
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 0, locationListener);
registerReceiver(myBroadCastreceiver, new IntentFilter(INTENT_FILTER_TAG));
} else if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
Log.i("Network_Enabled", "Network enable! listening for Network location.");
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10000, 0, locationListener);
registerReceiver(myBroadCastreceiver, new IntentFilter(INTENT_FILTER_TAG));
} else {
loadingDialog.dismiss();
Toast.makeText(this, "No Provider enable!", Toast.LENGTH_LONG).show();
}
}//End of onCreate......
/**
* My BroadCast Receiver, that is called when i get the location of user.
* #author Rupesh Yadav.
*
*/
class MyBroadCastreceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
//Remove location update when you get user`s location very first time.
locationManager.removeUpdates(locationListener);
//Remove the broadcast listener that update my location on map.
unregisterReceiver(myBroadCastreceiver);
GeoPoint point = new GeoPoint(latitude, longitude);
mapView.getController().animateTo(point);
List<Overlay> mapOverlays = mapView.getOverlays();
Drawable drawable = MyLocationOnMap.this.getResources().getDrawable(R.drawable.hs_mapoverlay);
itemizedoverlay = new MyLocationOverlay(drawable, MyLocationOnMap.this);
OverlayItem overlayitem = new OverlayItem(point, "Hello!", "My Current Location :)");
itemizedoverlay.addOverlay(overlayitem);
mapOverlays.add(itemizedoverlay);
loadingDialog.dismiss();
}
}
/**
* My Location listener...
*/
class MyLocationListener implements LocationListener{
#Override
public void onLocationChanged(Location location) {
latitude=(int) ((location.getLatitude())*1E6);
longitude=(int) ((location.getLongitude())*1E6);
//Send broadcast to update my location.
Intent sendLocationIntent=new Intent(INTENT_FILTER_TAG);
sendBroadcast(sendLocationIntent);
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
}
#Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
}
MyLocationOverlay class
public class MyLocationOverlay extends ItemizedOverlay<OverlayItem> {
Context mContext;
private ArrayList<OverlayItem> hsOverlays = new ArrayList<OverlayItem>();
public MyLocationOverlay(Drawable defaultMarker) {
super(boundCenterBottom(defaultMarker));
// TODO Auto-generated constructor stub
}
public MyLocationOverlay(Drawable defaultMarker, Context context) {
super(boundCenterBottom(defaultMarker));
mContext = context;
}
#Override
protected OverlayItem createItem(int i) {
// TODO Auto-generated method stub
return hsOverlays.get(i);
}
#Override
public int size() {
// TODO Auto-generated method stub
return hsOverlays.size();
}
/**
* add new OverlayItem objects to map OverlayItem ArrayList.
*
* #param overlay
*/
public void addOverlay(OverlayItem overlay) {
hsOverlays.add(overlay);
populate();
}
/**
* Called when user clicks on map overlay.
*/
#Override
protected boolean onTap(int index) {
// TODO Auto-generated method stub
// return super.onTap(index);
OverlayItem item = hsOverlays.get(index);
AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
dialog.setTitle(item.getTitle());
dialog.setMessage(item.getSnippet());
dialog.show();
return true;
}
You can modify the Location Listener & Broadcasr Receiver according to your need.
I hope this will solve your problem.
Best regards!
I have used this class for detecting my lat & lon:
Hope this is useful for you too.
Example how to use:
GPSUtility.getInstance(Context).getLatitude();
GPSUtility.getInstance(CamPhotoModeAct.this).getLongitude()
public class GPSUtility {
public static final String TAG = "GPSUtility";
private Context ctx;
Timer timer1;
LocationManager lm;
LocationResult locationResult;
boolean gps_enabled=false;
boolean network_enabled=false;
private double latitude;
private double longitude;
private static SharedPreferences SHARED_PREF;
private static SharedPreferences.Editor EDITOR_SHARED_PREF;
private static GPSUtility this_instance;
public GPSUtility(Context ctx){
this.ctx = ctx;
SHARED_PREF = ctx.getSharedPreferences(ConstantsG.SHARED_PREF_FILE, Context.MODE_PRIVATE);
EDITOR_SHARED_PREF = SHARED_PREF.edit();
this.getLocation(innerLocationResult);
}
public static GPSUtility getInstance(Context ctx){
if(this_instance == null)
this_instance = new GPSUtility(ctx);
return this_instance;
}
public static void updateLocation(Context ctx){
GPSUtility.getInstance(ctx);//this writes the latitude and longitude in sharable preference file
}
public double getLatitude(){
String latitudeStr = SHARED_PREF.getString(ConstantsG.KEY_LATITUDE,null);
if(latitudeStr == null){
latitude = 0.0;
}
else{
latitude = Double.parseDouble(latitudeStr);
}
return latitude;
}
public double getLongitude(){
String longitudeStr = SHARED_PREF.getString(ConstantsG.KEY_LONGITUDE,null);
if(longitudeStr == null){
longitude = 0.0;
}
else{
longitude = Double.parseDouble(longitudeStr);
}
return longitude;
}
private void updateWithNewLocation(Location location) {
if (location != null) {
latitude = location.getLatitude();
EDITOR_SHARED_PREF.putString(ConstantsG.KEY_LATITUDE, String.valueOf(latitude) );
longitude = location.getLongitude();
EDITOR_SHARED_PREF.putString(ConstantsG.KEY_LONGITUDE, String.valueOf(longitude));
EDITOR_SHARED_PREF.commit();
}
}
public boolean getLocation(LocationResult result)
{
//I use LocationResult callback class to pass location value from GPSUtility to user code.
locationResult=result;
if(lm==null)
lm = (LocationManager) this.ctx.getSystemService(Context.LOCATION_SERVICE);
//exceptions will be thrown if provider is not permitted.
try {
gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
} catch (Exception ex) {
Log.e(TAG, "Exception error: " + ex.getLocalizedMessage(), ex);
}
try {
network_enabled = lm
.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch (Exception ex) {
Log.e(TAG, "Exception error: " + ex.getLocalizedMessage(), ex);
}
//Toast.makeText(context, gps_enabled+" "+network_enabled, Toast.LENGTH_LONG).show();
//don't start listeners if no provider is enabled
if(!gps_enabled && !network_enabled){
Toast.makeText(this.ctx, "You should enable gps or be connected to network.", Toast.LENGTH_LONG).show();
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(), 10000);
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 {
#Override
public void run() {
//Context context = getClass().getgetApplicationContext();
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);
}
LocationResult innerLocationResult = new LocationResult() {
#Override
public void gotLocation(Location location) {
updateWithNewLocation(location);
}
};
}
I created this earlier on today, but it is not working. Location manager returns null, and I've even implemented the listener. Any ideas to the problems. thanks.
Edited:
I think this line is the problem
Location location = locationManager.getLastKnownLocation(provider);
Basically, if location is null, it will go into the else part of the if statement below it. Every time I compile the code, it will go into the else statement meaning it location is not updating.
public class Activity1 extends Activity implements LocationListener {
/** Called when the activity is first created. */
JoshTwoActivity main;
Activity2 two;
boolean checkTick = false;
String locationplace = "";
private LocationManager locationManager;
private String provider;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
provider = locationManager.getBestProvider(criteria, false);
System.out.println(provider);
System.out.println(locationManager.getProviders(criteria, false));
System.out.println(locationManager.getProvider("network"));
System.out.println(locationManager.getAllProviders());
Location location = locationManager.getLastKnownLocation(provider);
System.out.println(locationManager.isProviderEnabled(provider));
// Initialize the location fields
if (location != null) {
System.out.println("Provider " + provider + " has been selected.");
int lat = (int) (location.getLatitude());
int lng = (int) (location.getLongitude());
System.out.println(String.valueOf(lat));
System.out.println(String.valueOf(lng));
} else {
System.out.println("Provider not available");
System.out.println("Provider not available");
}
}
/* Request updates at startup */
#Override
protected void onResume() {
super.onResume();
locationManager.requestLocationUpdates(provider, 400, 1, this);
}
/* Remove the locationlistener updates when Activity is paused */
#Override
protected void onPause() {
super.onPause();
locationManager.removeUpdates(this);
}
#Override
public void onLocationChanged(Location location) {
int lat = (int) (location.getLatitude());
int lng = (int) (location.getLongitude());
System.out.println(String.valueOf(lat));
System.out.println(String.valueOf(lng));
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
Toast.makeText(this, "Enabled new provider " + provider,
Toast.LENGTH_SHORT).show();
}
#Override
public void onProviderDisabled(String provider) {
Toast.makeText(this, "Disenabled provider " + provider,
Toast.LENGTH_SHORT).show();
}
}
getLastKnownLocation() returns a location with the last known location fix for a provider. If the provider returns null, the provider has never had a location fix. It doesn't mean the provider is not available.
Once you call getLastKnownLocation() you should check to see if the results are accurate or recent enough for your purpose. If not you should request location updates using requestLocationUpdates().
This blog post contains everything you need to know about writing code using location providers.
http://android-developers.blogspot.com/2011/06/deep-dive-into-location.html
Ok my first guess is that you are not giving location fix via command line or by using eclipse DDMS perpective. If this is problem go open DDMS perpecive and give latitude and longtiude you want and send it. So location will not be null from now on if this is the problem.
The following link may help you in understanding how to use emulator in finding the location. The last section of this page has that information.
http://developer.android.com/guide/topics/location/obtaining-user-location.html