为啥 getSpeed() 在 android 上总是返回 0

Posted

技术标签:

【中文标题】为啥 getSpeed() 在 android 上总是返回 0【英文标题】:why getSpeed() always return 0 on android为什么 getSpeed() 在 android 上总是返回 0 【发布时间】:2011-06-16 06:20:00 【问题描述】:

我需要通过 GPS 获取速度和航向。但是,我从location.getSpeed() 获得的唯一数字是 0 或有时不可用。我的代码:

        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;

我尝试玩标准但没有成功。有谁知道问题出在哪里?

【问题讨论】:

【参考方案1】:

location.getSpeed() 仅返回使用 location.setSpeed() 设置的内容。这是您可以为位置对象设置的值。

要使用 GPS 计算速度,您需要做一些数学运算:

Speed = distance / time

所以你需要这样做:

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

全部转换为 ft/sec,或者您想要显示的速度。这就是我在制作跑步者应用时的做法。

更具体地说,您需要计算绝对距离:

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

创建一个新的 TrackPoint 类或其他东西可能会有所帮助,它将 GPS 位置和时间保存在里面。

【讨论】:

它会返回米还是公里的距离? 我看到 getSpeed() 返回零的问题,即使 'hasSpeed()' 为真并且有运动。在一台 6.0.1 设备上,它总是返回零!来自 Fused Location 服务。常规 LocationManager 提供速度,但似乎不太准确且更新频率较低。所以我按照这里的建议进行了自己的速度计算。 9 年后,这对我有用,location.speed (kotlin) 从 android Studio 模拟器位置路线运动返回了正确的结果(假设),但是,现实世界的驾驶总是返回 0 KM/H叮叮叮。 这个答案是错误的,它并不总是返回0,也不需要使用setSpeed()方法使其不为零。安卓无需你也能提速,无需人工计算【参考方案2】:

Imbru 的answer 看起来确实不错,但如果您使用单位,它就不是很有帮助。

这是我计算速度的方法,以米/秒 (m/s) 为单位。

object : LocationListener() 
    var previousLocation: Location? = null

    override fun onLocationChanged(location: Location) 
        val speed = if (location.hasSpeed()) 
            location.speed
         else 
            previousLocation?.let  lastLocation ->
                // Convert milliseconds to seconds
                val elapsedTimeInSeconds = (location.time - lastLocation.time) / 1_000.
                val distanceInMeters = lastLocation.distanceTo(location)
                // Speed in m/s
                distanceInMeters / elapsedTimeInSeconds
             ?: 0.0
        
        previousLocation = location

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

        . . .

    

    . . .


【讨论】:

只有location.hasSpeed()==false才应该进行速度计算。也有人报告location.getSpeed() 总是返回0,即使location.hasSpeed()==true。因此,我会使用location.hasSpeed() && location.getSpeed()>0 作为条件。 我第二次 Julien Kroneggs 建议更喜欢使用 direkt getSpeed(如果 .hasSpeed()==true),因为 GPS 不需要两个位置及其距离来计算速度,但可以使用多普勒效应来计算速度更准确。这意味着 getSpeed 在时间上会更准确,而距离/时间计算会随着两个位置之间经过的时间更长而变得更精确,但只会给您两个测量值之间的平均速度,而不是新位置进入时的速度. @JulienKronegg 报告说即使 hasSpeed 也可以为 0? @user924 你可以在 SO google.com/…找到一些帖子 @JulienKronegg mb 他们没有正确的检查(使用 hasSpeed)【参考方案3】:

我的自定义 LocationListener 用于手动获取速度,如果有速度,则通过位置对象获取速度。

 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) 

        
    ;

【讨论】:

我使用了你的代码,它的工作原理是这样的,它返回速度为 2.25,但我的车速约为 60km/h。如何准确计算移动速度? @Kevin ABRIOUX 计算速度的单位是什么。是公里/小时吗? 我建议使用 location.distanceTo(other_location) 的内置方法,而不是自行计算位置之间的距离。具有时间增量的除数可以保持不变。输出是米每秒,所以乘以 3.6 得到公里/小时 我错误地建议除数是正确的。但它以毫秒为单位计算时间增量,但速度以米每秒为单位。【参考方案4】:

在球形行星上的距离应该用这些公式计算:

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;
   

【讨论】:

如果用户在斜坡上怎么办?? 即使是谷歌似乎也忘记了海拔增量。也许是因为糟糕的卫星修复和蜂窝塔/wifi 只能提供 2D 位置?查看 Location.distanceTo 代码 - 我不完全理解 - 我可以看到两个位置的纬度和经度以及方位在起作用,但看不到高度。【参考方案5】:

(1) 我相信您可以使用requestLocationUpdates() 方法,然后创建一个LocationListener 类,并设置一个onLocationChange 方法来显示getSpeed()。这就是我最近看到使用 Location.getLatitude 和 Location.getLongitude 完成的方式,所以我相信您可以以同样的方式使用 getSpeed(),对吗?

(2) 但是,在刚刚阅读了 eclipse 描述窗口之后,我看到它与前人所说的完全一样:“如果 hasSpeed() 为假,则返回 0.0f。” 但也许这会有所帮助:http://www.ehow.com/how_5708473_convert-latitude-feet.html :)

【讨论】:

【参考方案6】:

getSpeed() 方法实际上工作得很好,但是你必须使用像 1 秒这样的高请求间隔并且你需要高精度,首先我做了 3 秒的间隔和 PRIORITY_BALANCED_POWER_ACCURACY,我一直得到 0 值,直到我像我说的那样改变它.我正在使用融合位置提供程序 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();
        
    

【讨论】:

我会假设使用融合的位置提供程序,您不会总是获得速度或非常糟糕的速度,因为如果 GPS 不良或没有 GPS,您将获得非常精确的三角单元塔或 wifi 附近读数准确性不准确,速度一定很糟糕。我建议仅在速度很高的情况下使用 GPS Prodiver。不过我不是专家,我只使用 GPS 以在 wifi 关闭的情况下省电。【参考方案7】:

嘿,我也遭受同样的痛苦,但现在我已经解决了! 只需将值乘以 18/5 即可得出几乎准确的值。

speed=location.getSpeed()*18/5

还将interval 指定为1000*2,将fastest interval 指定为1000*1 以提高准确性

【讨论】:

这个18/5 幻数从何而来?另外,这对 " getSpeed() 返回 0 " 的问题有什么帮助? getSpeed() 方法返回以 m/s 为单位的值,该值始终返回零,因此使用 18/5 1 m/s=18/5 Km/hr 转换为 km/h 一小时秒数 = 3600;以千米为单位的米 = 1000。因此 1 m/s = 3600/1000 km/h = 36/10 km/h = 18/5 km/h = 3.6 km/h。【参考方案8】:

getspeed() 工作正常。您不必使用距离公式进行数学计算。 getspeed里已经有了,只要有经纬度,getspeed里就会有速度。

【讨论】:

我不认为这是真的,我确实有经度和纬度,但 getSpeed() 总是返回 0.0【参考方案9】:

我之前也遇到过这个问题, 我希望这会有所帮助。

返回 0 是因为您的设备无法锁定 GPS,或无法连接到 GPS。

我尝试使用较旧的 lenovo 设备获取速度,但它返回 0,因为它无法锁定 gps。

我尝试使用三星 Galaxy nexus,它返回了我的速度(有更好的 GPS 传感器)。

您手机中的 GPS 传感器可能不好,或者您位于 GPS 信号较弱的区域,例如房屋或建筑物内。

【讨论】:

【参考方案10】:

我基本上计算瞬时速度,然后使用 setSpeed() 方法将其添加到位置。它非常准确,因为我在可以检查测速仪的车辆内进行了比较。

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;

【讨论】:

【参考方案11】:

根据此处的其他建议,我将这段代码与 cmets 放在一起,说明原因:

public static float getSpeedKmh(Location newLocation, Location previousLocation)

    if(newLocation == null) throw new IllegalArgumentException("newLocation must not be null");
    float speed = -1.0f;
    if(newLocation.hasSpeed()) /* gps doppler speed at the current moment preferred */
    
        speed = newLocation.getSpeed();
    else /* may be wifi or celltower based location: compute AVERAGE speed since last fix */
    
       if(previousLocation == null) throw new IllegalArgumentException("Cannot compute speed without previousLocation (was null)");
       if(previousLocation.getTime()==newLocation.getTime())
           throw new IllegalArgumentException("Cannot compute speed from same time locations!"); /* diff by zero protection */
       speed = newLocation.distanceTo(previousLocation) * 1000.0f /* time diff in millis so multiply by 1000 */
           / Math.abs(newLocation.getTime() - previousLocation.getTime()); /* Math abs: so you can even swap new and older location without effect */
    
       return speed * 3.6f; /* m/s -> km/h */

【讨论】:

以上是关于为啥 getSpeed() 在 android 上总是返回 0的主要内容,如果未能解决你的问题,请参考以下文章

为啥 location.getSpeed() 总是返回 0

如何获取Android设备用户移动的速度? Location.getSpeed 可靠吗?

位置的 getSpeed() 在 WiFi 上不起作用

计算没有 getSpeed() 方法的导航应用程序的速度

使用 Fused Location API,Marshmallow 不会使用 location.getSpeed()

从 2 点计算速度