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();
    String provider = _locManager.getBestProvider(criteria, true);

    if (provider == null || provider.equals("")) {
        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;

        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

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


        public void onProviderEnabled(String s) {


        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;

    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: 🙂


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;

protected void onCreate(Bundle savedInstanceState) {

    mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

protected void onResume() {
    if(!runtime_permissions()) {

protected void onPause() {
    //stop location updates when Activity is no longer active
    if (mFusedLocationClient != null) {

private void requestLocations(){
    LocationRequest mLocationRequest = new LocationRequest();

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

LocationCallback mLocationCallback = new LocationCallback() {
    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;

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){



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.


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;


    //System.out.println("Instantaneous Speed m/s: "+insSpeed);
    return insSpeed;

Leave a Reply

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