【问题标题】: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;
}

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

【问题讨论】:

    标签: android gps performance location


    【解决方案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】:

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

    这是我计算速度的方法,以米/秒 (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 */
          }
          

          【讨论】:

            猜你喜欢
            • 2021-01-24
            • 2016-09-16
            • 2020-05-25
            • 2013-02-26
            • 2013-06-25
            • 1970-01-01
            • 2013-02-14
            • 2011-12-13
            相关资源
            最近更新 更多