Very strange. When I stop my car, the TextView showing my velocity has a value greater than zero. That doesn't change until I drive again.
This is my code:
public void onLocationChanged(Location location) {
double dSpeed = location.getSpeed() * 3.6;
if(location.hasSpeed()) {
tvKmh.setText(String.valueOf((int)dSpeed));
} else {
tvKmh.setText("0");
}
}
There's no difference to that:
public void onLocationChanged(Location location) {
double dSpeed = location.getSpeed() * 3.6;
tvKmh.setText(String.valueOf((int)dSpeed));
}
How can I detect that there's no speed when location isn't changed?
LocationManager is defined like this:
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 10, this);
Maybe you need a TimerTask that checks if the current location's speed is zero and updates accordingly. Maybe run it once a second.
Related
...or most probably, I am doing it wrong. What I want is to display a Toast every one meter I walk inside home. The code below gives me wrong results, as the moment I install the app on my phone I get a Toast without even moving!
public class MainActivity extends Activity {
private LocationListener mLocationListener;
private String mLocationProvider;
private LocationManager mLocationManager;
private Location mCurrentLocation;
private int mCounter = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
mLocationListener = new MyLocationListener();
Criteria criterion = new Criteria();
criterion.setAccuracy(Criteria.ACCURACY_FINE);
criterion.setCostAllowed(true);
criterion.setPowerRequirement(Criteria.POWER_HIGH);
mLocationProvider = mLocationManager.getBestProvider(criterion, true);
}
#Override
protected void onResume() {
super.onResume();
mCurrentLocation = mLocationManager.getLastKnownLocation(mLocationProvider);
mLocationManager.requestLocationUpdates(mLocationProvider, 5000, 1, mLocationListener);
}
#Override
protected void onPause() {
super.onPause();
mLocationManager.removeUpdates(mLocationListener);
}
private class MyLocationListener implements LocationListener {
#Override
public void onLocationChanged(Location newlocation) {
float distance = mCurrentLocation.distanceTo(newlocation);
if (distance >= 1) {
mCounter++;
Toast.makeText(MainActivity.this, String.format("Message #%d: you walked one more meter", mCounter), Toast.LENGTH_SHORT).show();
mCurrentLocation = newlocation;
}
}
}
}
A GPS signal is not precise enough to give exact locations for a 1m radius. There can be deviation peeks up to 50 - 100m in real situations using GPS. This depends much on the environment you are at. GPS will be reflected by buildings, water etc. An average deviation is 10 - 20m. This will get even worse if your inside of a building using a GPS provider instead of a Network provider.
Furthermore you will never get the same coordinates twice in a row, because of this. Even if you don't move! To avoid that you could temporarly save the location and compare it with the new location. If the distance between them hits a defined boarder use the new location.
Change your location provider to GPS. And you have instantiated the LocationListener before you request the new Location(in onResume(); onResume() will be called after onCreate()). This might be the reason for your app showing Toast on start up.. Try to instantiate LocationListener after the requestLocationUpdates()..
my target is to get periodically location updates from network provider using requestlocationupdate() method during certain intervals(x sec), then execute LocationManager.removeUpdates() method to remove updates and achieve an power consumption to be as minimum as possible,
the problem which faced me is the requestlocationupdate() method invoked and call onlocationchanged method every 45 sec, even its "mintime" (2nd parameter in this method) is less than 45 !!, why this happen?
also, the 2nd problem is during each interval, i need to invoke the requestlocationupdates method and records the current latitude and longitude of the user's location and compare it with the recorded latitude and longitude of the last location, if its the same(user still stationary), display "your last location is ...", if happen an change in the location, display "your updated location is ...." .
how i can do it ?
i tried to solve this problem using use handler.post(myRunnable) and calling an runnable object with timertask class to execute requestlocationupdates() method every (x sec) which determined in timertask input parameters.
when i tested this code, its get the latitude and longitude every x sec but its recorded values are changes even i still in the same location!
also,is writing any code in onlocationchanged() override method represents a good approach from side of energy saving?
also, can you tell me how i can get the accuracy of any network provider (wifi/ 3G)?
Any help will be very much appreciated!
Code is looks like:
intializations:
Timer t1;
Timer t2;
TimerTask mTimerTask1;
TimerTask mTimerTask2;
Handler hand;
Handler hand1;
public LocationManager locationManager;
// flag for GPS status
boolean isGPSEnabled = false;
// flag for network status
boolean isNetworkEnabled = false;
Location location; // location
double latitude; // latitude
double longitude; // longitude
double Altitude; // longitude
double accuracy; // accuracy
// The minimum distance to change notifications Updates in meters
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 0; // 0 meters
// The minimum time between notifications updates in milliseconds
private static final long MIN_TIME_BW_UPDATES = 10; // 10 sec
Handler part:
Runnable run1 = new Runnable() {
public void run() {
mTimerTask1 = new TimerTask() {
public void run() {
hand.post(new Runnable() {
public void run() {
if(check_conectivity()){
//flag1=false;
get_location();
time++;
}
}
});
}
};
t1.scheduleAtFixedRate(mTimerTask1, 0, 10000);
}
};
check_connectivity method:
public boolean check_conectivity(){
// put the reference LocationManger
locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
// getting network status
// isProviderEnabled ==> Returns the current enabled/disabled status of the NETWORK_PROVIDERr.
// If the user has enabled this provider in the Settings menu, true is returned otherwise false is returned
isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if ( !isNetworkEnabled) {
// no network provider is enabled
showSettingsAlert();
return false;
}
else{
return true;
}
}
get_location method:
public void get_location(){
if (isNetworkEnabled) {
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,MIN_TIME_BW_UPDATES,MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
Log.d("Network", "Network");
onlocationchanged() override method:
if (locationManager!= null){
location = locationManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
tv2.setText("Your last Location is - \nLat: " + latitude + "\nLong: " + longitude );
tv3.setText("Last estimeted location number : " + time1);
time1++;
stopUpdating();
can you tell me how i can get the accuracy of any network provider (wifi/ 3G)
As I know you can't. But you can filter responses and tell to device to notify you only if accuracy is ..... .
1st off you can use postDelayed instead post:
private int mSampleDurationTime = 10000; // 10 sec for example
...
mHandler.postDelayed(mRunnable, mSampleDurationTime);`
2nd you can try to get "best location" described in one of my answers, see link here
hope it will help you,
I have following code:
LocationManager mlocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
LocationListener mlocListener = new MyLocationListener();
mlocManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
and MyLocationListener class:
public class MyLocationListener implements LocationListener{
#Override
public void onLocationChanged(Location loc){
loc.getLatitude();
loc.getLongitude();
tv_GPSlat.setText("Latitude: " + loc.getLatitude());
tv_GPSlon.setText("Longitude: " + loc.getLongitude());
}
#Override
public void onProviderDisabled(String provider){
Toast.makeText( getApplicationContext(),"GPS is not working", Toast.LENGTH_SHORT ).show();
}
#Override
public void onProviderEnabled(String provider){
Toast.makeText( getApplicationContext(),"GPS is working",Toast.LENGTH_SHORT).show();
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras){
}
}
I would like to save current longitude and latitude to my TextViews (tv_GPSlat, tv_GPSlon) but the location values are not constant (they are changing all the time). How can I do this?
GPS isn't exact- even if you don't move it will bounce around a bit. Just put up the first location you get, and ignore future updates unless they move by more than a certain amount. That's the easiest way to do it.
You have to get the location and once you get it (i.e. your handler method is invoked) you have to unregister the handler in order to stop receiving the updates. Simply add this line at the end of your handler method onLocationChanged() in MyLocationListener:
LocationManager mlocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
mlocManager.removeUpdates(this);
Add a data member to your location listener, and keep the previous location in it:
public class MyLocationListener implements LocationListener {
public Location mSavedLocation;
#Override
public void onLocationChanged(Location loc) {
// If we don't have saved location, or the distance between
// the saved location and the new location is bigger than
// 5 meters (~15ft) save the new location
if ((mSavedLocation == null) ||
(loc.distanceTo(mSavedLocation) > 5)) {
mSavedLocation = loc;
}
// Update the screen with the current saved location
tv_GPSlat.setText("Latitude: " + mSavedLocation.getLatitude());
tv_GPSlon.setText("Longitude: " + mSavedLocation.getLongitude());
}
// ... no changes to the rest of the class
}
Now the rest of your code can also get the latest saved location using:
mlocListener.mSavedLocation
I wonder why no one mentioned this. May be I a missing something. The call you have made has 0,0. It should have milliseconds, distanceinmeters. This way location change is only called when a particular distance is traveled OR after a time out. I am using both GPS and NETWORK providers to not be dependent on either too (sometimes GPS is not reliable).
LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, God.KM20TIME,
God.KM20DISTANCE, (LocationListener) updates);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, God.KM20TIME,
God.KM20DISTANCE, (LocationListener) updates);
I'm developing an application that needs to get location updates fast, doesn't matter the accuracy of them. I need to be able to get about one reading per second. How can I do this?
Other than specifying 0 for both the minimum distance and minimum time values in requestLocationUpdates(), you have no control over the rate. Android will give you all of the fixes it receives, but whether that is 30 fixes per second or 30 seconds per fix will depend upon hardware, environment (e.g., is the user indoors?), and so forth.
You could build a layer between the Android location updates and your receiver.
In your own layer, catch the Android location updates, and pass the same location 30 times per second to your receiver, until you get a new location.
EDIT
Something like this (not tested):
public class MyLocationManager implements LocationListener{
private List<MyLocationListener> listeners;
private Location lastLocation;
private Handler handler;
public MyLocationManager(){
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
lastLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
listeners = new ArrayList<MyLocationListener>();
handler = new Handler();
sendLocationUpdates();
}
private void sendDelayedLocationUpdates(){
handler.postDelayed(locationUpdater, 200);
}
public void addMyLocationListener(MyLocationListener mListener){
listeners.add(mListener);
}
public void removeMyLocationListener(MyLocationListener mListener){
listeners.remove(mListener);
}
#Override
public void onLocationChanged(Location location) {
lastLocation = location;
}
public interface MyLocationListener{
public void onLocationChanged(Location location);
}
private Runnable locationUpdater = new Runnable(){
#Override
public void run(){
for(MyLocationListener mListener : listeners){
mListener.onLocationChanged(lastLocation);
}
sendDelayedLocationUpdates();
}
};
}
my app need use new current GPS parameter(update after each from 3 to 8 second): latitude and longitude. and i am using both: GPS-provider and Network-provider.
i know use to update the GPS parameters
if(gps_enabled)
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
if(network_enabled)
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
The Problem: in fact, the gps update after each environ 40-50 second
How can i get the GPS update after 3-8 seconds ??
thanks you
try{gps_enabled=lm.isProviderEnabled(LocationManager.GPS_PROVIDER);}catch(Exception ex){}
try{network_enabled=lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);}catch(Exception ex){}
//lm is locationManager
In fact. i don't use the condition: network_enabled or Network-provider to get Location. ---> It work and the new code:
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 0, locationListenerGps);
The reason, i don't use the Network_Provider. Because, when 2 GPS and Network Provider, system will use the NEtwork_provider. But in the logcat, i see that Smartphone does not update"Listenter" loop 3-6s with Network_provider.
En revanche, with GPS_PROVIDER, smartphone update alway 3-6s.
-- First time when open GPS; i need 30-50second to have the first Listener. But it is OK
I've written a little app that will return position, average speed and current speed. When I run it on my phone (HTC Legend) it updates 1-2 times a second. You're more than welcome to use it if you like. you just need to create a main.xml file with 6 textviews and then add this line to your AndroidManifest.xmll file:
package Hartford.gps;
import java.math.BigDecimal;
import android.app.Activity;
import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.TextView;
public class GPSMain extends Activity implements LocationListener {
LocationManager locationManager;
LocationListener locationListener;
//text views to display latitude and longitude
TextView latituteField;
TextView longitudeField;
TextView currentSpeedField;
TextView kmphSpeedField;
TextView avgSpeedField;
TextView avgKmphField;
//objects to store positional information
protected double lat;
protected double lon;
//objects to store values for current and average speed
protected double currentSpeed;
protected double kmphSpeed;
protected double avgSpeed;
protected double avgKmph;
protected double totalSpeed;
protected double totalKmph;
//counter that is incremented every time a new position is received, used to calculate average speed
int counter = 0;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
run();
}
#Override
public void onResume() {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 1, this);
super.onResume();
}
#Override
public void onPause() {
locationManager.removeUpdates(this);
super.onPause();
}
private void run(){
final Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setSpeedRequired(true);
criteria.setAltitudeRequired(false);
criteria.setBearingRequired(false);
criteria.setCostAllowed(true);
criteria.setPowerRequirement(Criteria.POWER_LOW);
//Acquire a reference to the system Location Manager
locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
// Define a listener that responds to location updates
locationListener = new LocationListener() {
public void onLocationChanged(Location newLocation) {
counter++;
//current speed fo the gps device
currentSpeed = round(newLocation.getSpeed(),3,BigDecimal.ROUND_HALF_UP);
kmphSpeed = round((currentSpeed*3.6),3,BigDecimal.ROUND_HALF_UP);
//all speeds added together
totalSpeed = totalSpeed + currentSpeed;
totalKmph = totalKmph + kmphSpeed;
//calculates average speed
avgSpeed = round(totalSpeed/counter,3,BigDecimal.ROUND_HALF_UP);
avgKmph = round(totalKmph/counter,3,BigDecimal.ROUND_HALF_UP);
//gets position
lat = round(((double) (newLocation.getLatitude())),3,BigDecimal.ROUND_HALF_UP);
lon = round(((double) (newLocation.getLongitude())),3,BigDecimal.ROUND_HALF_UP);
latituteField = (TextView) findViewById(R.id.lat);
longitudeField = (TextView) findViewById(R.id.lon);
currentSpeedField = (TextView) findViewById(R.id.speed);
kmphSpeedField = (TextView) findViewById(R.id.kmph);
avgSpeedField = (TextView) findViewById(R.id.avgspeed);
avgKmphField = (TextView) findViewById(R.id.avgkmph);
latituteField.setText("Current Latitude: "+String.valueOf(lat));
longitudeField.setText("Current Longitude: "+String.valueOf(lon));
currentSpeedField.setText("Current Speed (m/s): "+String.valueOf(currentSpeed));
kmphSpeedField.setText("Cuttent Speed (kmph): "+String.valueOf(kmphSpeed));
avgSpeedField.setText("Average Speed (m/s): "+String.valueOf(avgSpeed));
avgKmphField.setText("Average Speed (kmph): "+String.valueOf(avgKmph));
}
//not entirely sure what these do yet
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
// Register the listener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 1, locationListener);
}
//Method to round the doubles to a max of 3 decimal places
public static double round(double unrounded, int precision, int roundingMode)
{
BigDecimal bd = new BigDecimal(unrounded);
BigDecimal rounded = bd.setScale(precision, roundingMode);
return rounded.doubleValue();
}
#Override
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
}
#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
}
}
The minTime parameter of requestLocationUpdates should be 3000 to 8000
public void requestLocationUpdates (String provider, long minTime, float minDistance, LocationListener listener, Looper looper)
minTime the minimum time interval for notifications, in milliseconds. This field is only used as a hint to conserve power, and actual time between location updates may be greater or lesser than this value.
minDistance the minimum distance interval for notifications, in meters
Take a look at requestLocationUpdates(...)
public void requestLocationUpdates (String provider, long minTime, float minDistance, LocationListener listener)
Since: API Level 1
Registers the current activity to be notified periodically by the named provider. Periodically, the supplied LocationListener will be called with the current Location or with status updates.
It may take a while to receive the most recent location. If an immediate location is required, applications may use the getLastKnownLocation(String) method.
In case the provider is disabled by the user, updates will stop, and the onProviderDisabled(String) method will be called. As soon as the provider is enabled again, the onProviderEnabled(String) method will be called and location updates will start again.
The frequency of notification may be controlled using the minTime and minDistance parameters. If minTime is greater than 0, the LocationManager could potentially rest for minTime milliseconds between location updates to conserve power. If minDistance is greater than 0, a location will only be broadcasted if the device moves by minDistance meters. To obtain notifications as frequently as possible, set both parameters to 0.
Background services should be careful about setting a sufficiently high minTime so that the device doesn't consume too much power by keeping the GPS or wireless radios on all the time. In particular, values under 60000ms are not recommended.
The calling thread must be a Looper thread such as the main thread of the calling Activity.
Parameters
provider the name of the provider with which to register
minTime the minimum time interval for notifications, in milliseconds. This field is only used as a hint to conserve power, and actual time between location updates may be greater or lesser than this value.
minDistance the minimum distance interval for notifications, in meters
listener a {#link LocationListener} whose onLocationChanged(Location) method will be called for each location update