gps – why getSpeed() always return 0 on android-ThrowExceptions

Exception or error:

I need to get the speed and heading from the gps. However the only number i have from location.getSpeed() is 0 or sometimes not available. my code:

        String provider = initLocManager();
    if (provider == null)
        return false;
    LocationListener locListener = new LocationListener() {
        public void onLocationChanged(Location location) {
            updateWithNewLocation(location, interval, startId);
            Log.i(getString(R.string.logging_tag), "speed =" + location.getSpeed());
        }

        public void onProviderDisabled(String provider){
            updateWithNewLocation(null, interval, startId);
        }

        public void onProviderEnabled(String provider) {}
        public void onStatusChanged(String provider, int status, Bundle extras) {}
    };

    _locManager.requestLocationUpdates(provider, interval,  DEFAULT_GPS_MIN_DISTANCE, locListener);


    private String initLocManager() {
    String context = Context.LOCATION_SERVICE;
    _locManager = (LocationManager) getSystemService(context);

    Criteria criteria = new Criteria();
    criteria.setAccuracy(Criteria.ACCURACY_FINE);
    criteria.setAltitudeRequired(false);
    criteria.setBearingRequired(true);
    criteria.setSpeedRequired(true);
    criteria.setCostAllowed(true);
    //criteria.setPowerRequirement(Criteria.POWER_LOW);
    String provider = _locManager.getBestProvider(criteria, true);

    if (provider == null || provider.equals("")) {
        displayGPSNotEnabledWarning(this);
        return null;
    }

    return provider;
}

I tried to play the Criteria with but no success. Does anyone have an idea what is the problem?

How to solve:

location.getSpeed() only returns what was set with location.setSpeed(). This is a value that you can set for a location object.

To calculate the speed using GPS, you’ll have to do a little math:

Speed = distance / time

So you would need to do:

(currentGPSPoint - lastGPSPoint) / (time between GPS points)

All converted to ft/sec, or however you want to show the speed. This is how I did it when I made a runner app.

More specifically, you’ll need to calculate for absolute distances:

(sqrt((currentGPSPointX - lastGPSPointX)^2) + (currentGPSPointY - lastGPSPointY)^2)) / (time between GPS points)

It might help to make a new TrackPoint class or something, which keeps the GPS location and time it was taken inside.

###

There is my custom LocationListener used to get speed manually and by location object if has speed.

 new LocationListener() {
        private Location mLastLocation;

        @Override
        public void onLocationChanged(Location pCurrentLocation) {
            //calcul manually speed
            double speed = 0;
            if (this.mLastLocation != null)
                speed = Math.sqrt(
                        Math.pow(pCurrentLocation.getLongitude() - mLastLocation.getLongitude(), 2)
                                + Math.pow(pCurrentLocation.getLatitude() - mLastLocation.getLatitude(), 2)
                ) / (pCurrentLocation.getTime() - this.mLastLocation.getTime());
            //if there is speed from location
            if (pCurrentLocation.hasSpeed())
                //get location speed
                speed = pCurrentLocation.getSpeed();
            this.mLastLocation = pCurrentLocation;
            ////////////
            //DO WHAT YOU WANT WITH speed VARIABLE
            ////////////
        }

        @Override
        public void onStatusChanged(String s, int i, Bundle bundle) {

        }

        @Override
        public void onProviderEnabled(String s) {

        }

        @Override
        public void onProviderDisabled(String s) {

        }
    };

###

Imbru‘s answer looks really good, but it is not very helpful if you are working with units.

Here’s what I did to calculate the speed in meters per second (m/s).

new LocationListener() {
    private Location lastLocation = null;
    private double calculatedSpeed = 0;

    @Override
    public synchronized void onLocationChanged(Location location) {
        if (lastLocation != null) {
            double elapsedTime = (location.getTime() - lastLocation.getTime()) / 1_000; // Convert milliseconds to seconds
            calculatedSpeed = lastLocation.distanceTo(location) / elapsedTime;
        }
        this.lastLocation = location;

        double speed = location.hasSpeed() ? location.getSpeed() : calculatedSpeed;

        /* There you have it, a speed value in m/s */

        . . .

    }

    . . .

}

###

On a spherical planet distance should be calculated with these formulas :

private static Double distance(Location one, Location two) {
       int R = 6371000;        
       Double dLat = toRad(two.getLatitude() - one.getLatitude());
       Double dLon = toRad(two.getLongitude() - one.getLongitude());
       Double lat1 = toRad(one.getLatitude());
       Double lat2 = toRad(two.getLatitude());         
       Double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
               + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);        
       Double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));        
       Double d = R * c;
       return d;
   }
private static double toRad(Double d) {
       return d * Math.PI / 180;
   }

###

(1) I believe you can use the requestLocationUpdates() method and then create a LocationListener class with an onLocationChange method set to display getSpeed(). This is how i recently saw it done with Location.getLatitude and Location.getLongitude, so I believe you could just use getSpeed() the same way, correct?

(2) After just reading the eclipse description window, though, I see it says exactly what the previous person said: “if hasSpeed() is false, 0.0f is returned.”
But maybe this will help: http://www.ehow.com/how_5708473_convert-latitude-feet.html 🙂

###

getSpeed() method actually works fine but you have to use a high request interval like 1 second and you need high accuracy, first i was doing 3 second interval and PRIORITY_BALANCED_POWER_ACCURACY and i kept getting 0 values until i change it like i say. I am using fused location provider api.

public class Main3Activity extends AppCompatActivity {

private FusedLocationProviderClient mFusedLocationClient;
private int speed;
private double lat;
private double lng;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2);

    mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
}

@Override
protected void onResume() {
    super.onResume();
    if(!runtime_permissions()) {
        requestLocations();
    }
}

@Override
protected void onPause() {
    super.onPause();
    //stop location updates when Activity is no longer active
    if (mFusedLocationClient != null) {
        mFusedLocationClient.removeLocationUpdates(mLocationCallback);
    }
}

@SuppressLint("MissingPermission")
private void requestLocations(){
    LocationRequest mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(1000);;
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

    mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
}

LocationCallback mLocationCallback = new LocationCallback() {
    @Override
    public void onLocationResult(LocationResult locationResult) {
        List<Location> locationList = locationResult.getLocations();
        if (locationList.size() > 0) {
            //The last location in the list is the newest
            Location location = locationList.get(locationList.size() - 1);

            lat = location.getLatitude();
            lng = location.getLongitude();

            //speed in km/h
            speed = (int) ((location.getSpeed() * 3600) / 1000);

        }
    }
};

private boolean runtime_permissions() {
    if(Build.VERSION.SDK_INT >= 23 && ContextCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){

        requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION},100);

        return true;
    }
    return false;
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if(requestCode == 100){
        if( grantResults[0] == PackageManager.PERMISSION_GRANTED){
            onResume();
        }else{
            runtime_permissions();
        }
    }
}

}

###

Hey I too was suffering from the same but now I have got it solved !
Just multiply the value by 18/5 , it gives almost the accurate value.

speed=location.getSpeed()*18/5

Also specify the interval as 1000*2 and fastest interval as 1000*1 for more accuracy

###

getspeed() works fine. You don’t have to do the math using distance formula. It is already there in getspeed, As long as there are latitude and longitude, there will be a speed in getspeed.

###

I also encountered this problem before,
I hope this can help.

It returns 0 because your device cannot get a lock on the GPS, or cannot connect to the GPS.

I tried to get the speed using an older lenovo device and it returns 0 because it cannot lock on a gps.

I tried using a samsung galaxy nexus and it returned my speed(has a better GPS sensor).

The GPS sensor in your phone might not be good or you are in an area that has a weak GPS signal such as inside a house or building.

###

I basicaslly calculate the instantaneous speed and then use the setSpeed() method to add it in the location. Its pretty accurate because I compared it inside a vehicle where I could check the tachymeter.

private double calculateInstantaneousSpeed(Location location) {



    double insSpeed = 0;
    if (y1 == null && x1 <= -1) {
        //mark the location y1 at time x1
        y1 = location;
        x1 = duration.getDurationAsSeconds();


    } else {
         //mark the location y2 at time x2
        y2 = location;
        x2 = duration.getDurationAsSeconds();


        //calculate the slope of the curve (instantaneous speed)
        dy = y1.distanceTo(y2);
        dx = x2 - x1;

        insSpeed = dy / dx;

        y1 = y2;
        x1 = x2;

    }

    Singleton.getInstance().instantaneousSpeedSamples.add(insSpeed);
    //System.out.println("Instantaneous Speed m/s: "+insSpeed);
    return insSpeed;
}

Leave a Reply

Your email address will not be published. Required fields are marked *