【问题标题】:How can I check the current status of the GPS receiver?如何查看 GPS 接收器的当前状态?
【发布时间】:2011-01-02 12:46:45
【问题描述】:

如何查看 GPS 接收器的当前状态?我已经检查了 LocationListener onStatusChanged 方法,但不知何故,它似​​乎不起作用,或者只是错误的可能性。

基本上我只需要知道屏幕顶部的 GPS 图标是闪烁(没有实际修复)还是稳定(修复可用)。

【问题讨论】:

    标签: android gps


    【解决方案1】:

    作为 SpeedView:Android 版 GPS 车速表的开发者,我一定尝试了所有可能的解决方案来解决这个问题,但结果都是一样的。让我们重申一下什么是行不通的:

    1. onStatusChanged() 不会在 Eclair 和 Froyo 上被调用。
    2. 当然,只计算所有可用卫星是没有用的。
    3. 检查是否有任何卫星为 usedInFix() 返回 true 也不是很有帮助。系统显然失去了修复,但不断报告其中仍有几个 sats 正在使用中。

    这是我找到的唯一可行的解​​决方案,也是我在应用程序中实际使用的解决方案。假设我们有一个实现 GpsStatus.Listener 的简单类:

    private class MyGPSListener implements GpsStatus.Listener {
        public void onGpsStatusChanged(int event) {
            switch (event) {
                case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
                    if (mLastLocation != null)
                        isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;
    
                    if (isGPSFix) { // A fix has been acquired.
                        // Do something.
                    } else { // The fix has been lost.
                        // Do something.
                    }
    
                    break;
                case GpsStatus.GPS_EVENT_FIRST_FIX:
                    // Do something.
                    isGPSFix = true;
    
                    break;
            }
        }
    }
    

    好的,现在在 onLocationChanged() 我们添加以下内容:

    @Override
    public void onLocationChanged(Location location) {
        if (location == null) return;
    
        mLastLocationMillis = SystemClock.elapsedRealtime();
    
        // Do something.
    
        mLastLocation = location;
    }
    

    就是这样。基本上,这就是完成所有工作的那一行:

    isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;
    

    您当然可以调整毫秒值,但我建议将其设置为 3-5 秒左右。

    这确实有效,虽然我没有查看绘制原生 GPS 图标的源代码,但这接近于复制它的行为。希望这对某人有所帮助。

    【讨论】:

    • 嗨,我想知道为什么在这个例子中计算可用卫星没有用?如果找到的卫星数量为 0 表示没有连接,还是我错了? groups.google.com/group/android-developers/browse_thread/thread/…
    • 嗨斯蒂芬,你能解释一下为什么是GPSFix的作品。谢谢,尼克
    • 顺便说一句,我注意到在 ICS 中,他们增加了系统开始报告 GPS 定位已丢失的时间。至少在 4.0.3 中正好是 10 秒。
    • 效果很好,使用 10 秒而不是 ICS 的 3-5 秒也很有效。幸运的是,修复不是我的应用程序的必要功能,但能够知道它是件好事。谢谢。
    • 但是当mLastLocationMillis 是由 GPS 以外的来源设置时,这不会中断吗?系统会声称 isGPSFix 是真的,但实际上它只是任何修复(可能来自电话网络)
    【解决方案2】:

    GPS 图标似乎会根据收到的广播意图更改其状态。您可以使用以下代码示例自行更改其状态:

    通知 GPS 已启用:

    Intent intent = new Intent("android.location.GPS_ENABLED_CHANGE");
    intent.putExtra("enabled", true);
    sendBroadcast(intent);
    

    通知 GPS 正在接收修复:

    Intent intent = new Intent("android.location.GPS_FIX_CHANGE");
    intent.putExtra("enabled", true);
    sendBroadcast(intent);
    

    通知 GPS 不再接收修复:

    Intent intent = new Intent("android.location.GPS_FIX_CHANGE");
    intent.putExtra("enabled", false);
    sendBroadcast(intent);
    

    通知 GPS 已被禁用:

    Intent intent = new Intent("android.location.GPS_ENABLED_CHANGE");
    intent.putExtra("enabled", false);
    sendBroadcast(intent);
    

    将接收者注册到意图的示例代码:

    // MyReceiver must extend BroadcastReceiver
    MyReceiver receiver = new MyReceiver();
    IntentFilter filter = new IntentFilter("android.location.GPS_ENABLED_CHANGE");
    filter.addAction("android.location.GPS_FIX_CHANGE");
    registerReceiver(receiver, filter);
    

    通过接收这些广播意图,您可以注意到 GPS 状态的变化。但是,只有在状态发生变化时才会通知您。因此,无法使用这些意图确定当前状态。

    【讨论】:

    • 我不知道您如何能够从您的应用程序发送该广播,因为它似乎是受系统保护的广播,这意味着只有系统可以发送它。任何发送该意图的应用都应该崩溃。
    • 六年前我写答案的时候就可以发了。显然,他们从那时起为系统增加了一些保护。
    • 我使用这些意图来判断其他应用程序何时使用 GPS。我相信从牛轧糖开始,你甚至不能再听这些意图了,或者他们已经改变了!我不想用我自己的应用程序监听位置。有人有其他想法吗?
    • 是的,我遇到了崩溃:05-14 10:25:24.113 17344-17344/xxx.yyy.zzz.debug E/AndroidRuntime: FATAL EXCEPTION: main Process: xxx.yyy.zzz .debug, PID: 17344 java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.location.GPS_FIX_CHANGE from pid=17344, uid=10416
    【解决方案3】:

    新成员很遗憾我无法发表评论或投票,但是 Stephen Daye 上面的帖子是解决我一直在寻求帮助的完全相同的问题的完美解决方案。

    以下行的小改动:

    isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;
    

    到:

    isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < (GPS_UPDATE_INTERVAL * 2);
    

    基本上就像我在构建一个慢节奏的游戏并且我的更新间隔已经设置为 5 秒,一旦 gps 信号输出超过 10 秒,那就是触发某些东西的正确时间。

    干杯伙伴,在我找到你的帖子之前花了大约 10 个小时试图解决这个解决方案 :)

    【讨论】:

      【解决方案4】:

      好的,让我们尝试结合目前所有的答案和更新,然后执行以下操作:

      GPS 监听器可能是这样的:

      GpsStatus.Listener listener = new GpsStatus.Listener() {
          void onGpsStatusChanged(int event) {
              if (event == GPS_EVENT_SATELLITE_STATUS) {
                  GpsStatus status = mLocManager.getGpsStatus(null);
                  Iterable<GpsSatellite> sats = status.getSatellites();
                  // Check number of satellites in list to determine fix state
              }
          }
      }
      

      API 有点不清楚何时以及提供哪些 GPS 和卫星信息,但我认为一个想法是查看有多少卫星可用。如果它低于三个,那么你就无法修复。如果它更多,那么你应该有一个修复。

      反复试验可能是确定 Android 报告卫星信息的频率以及每个 GpsSatellite 对象包含哪些信息的方法。

      【讨论】:

      • 计算可用卫星的问题是,即使您有 5 颗卫星在视野中,这并不意味着总有可能修复。 (您通过写“如果它更多,那么您应该有一个修复”提到它是正确的)
      • 确实如此。虽然我不知道更多关于构成修复需要哪些信息,或者如何/是否可以从 GpsSatellite 对象中检索。
      • 另一个想法..您在问题中没有提到这一点,但是您是否尝试过仅使用 LocationManager.requestLocationUpdates 并将时间和距离设置设置为 0?这应该会在它们发生时立即向您发送 GPS 修复。如果您没有收到任何东西,那么您很可能没有修复程序。如果您愿意,可以将其与上面的状态监听器结合使用。
      • 迭代“sats”并检查 GpsSatellite 中的 usedInFix() 可能吗?
      【解决方案5】:

      在 windows mobile 上使用 GPS 几年后,我意识到“丢失” GPS 定位的概念可能是主观的。要简单地听听 GPS 告诉您的内容,添加 NMEAListener 并解析句子将告诉您修复是否“有效”。见http://www.gpsinformation.org/dale/nmea.htm#GGA。不幸的是,对于某些 GPS,即使在“良好定位”区域的正常操作过程中,该值也会来回波动。

      因此,另一种解决方案是将 GPS 位置的 UTC 时间与手机时间(转换为 UTC)进行比较。如果它们之间存在一定的时差,您可以假设您丢失了 GPS 位置。

      【讨论】:

      • 您能解释一下时间比较方法吗?在 Stephen Daye 的回答中,他比较了上次修复发生时间与最新 GPS_EVENT_SATELLITE_STATUS 事件之间的时间差......不确定它测量的是什么。
      【解决方案6】:

      在处理我的 MSc 项目时遇到类似问题,似乎 Daye 的答案错误地报告了“没有修复”,而设备保持在静态位置。我已经稍微修改了解决方案,这在静态位置对我来说似乎工作得很好。我不知道它会如何影响电池,因为它不是我主要关心的问题,但这是我通过在修复超时时重新请求位置更新来做到这一点的。

      private class MyGPSListener implements GpsStatus.Listener {
          public void onGpsStatusChanged(int event) {
              switch (event) {
              case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
                  if (Global.getInstance().currentGPSLocation != null)
                  {
                      if((SystemClock.elapsedRealtime() - mLastLocationMillis) < 20000)
                      {
                          if (!hasGPSFix) 
                              Log.i("GPS","Fix Acquired");
                          hasGPSFix = true;
                      } 
                      else
                      {
                          if (hasGPSFix) 
                          {
                              Log.i("GPS","Fix Lost (expired)");
                              lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 10, locationListener);
                          }
                          hasGPSFix = false;
                      }
                  }
                  break;
              case GpsStatus.GPS_EVENT_FIRST_FIX:
                  Log.i("GPS", "First Fix/ Refix");
                  hasGPSFix = true;
                  break;
              case GpsStatus.GPS_EVENT_STARTED:
                  Log.i("GPS", "Started!");
                  break;
              case GpsStatus.GPS_EVENT_STOPPED:
                  Log.i("GPS", "Stopped");
                  break;
              }
          }
      }
      

      【讨论】:

        【解决方案7】:

        好吧,将所有工作方法放在一起会导致这种情况(同时处理已弃用的GpsStatus.Listener):

        private GnssStatus.Callback mGnssStatusCallback;
        @Deprecated private GpsStatus.Listener mStatusListener;
        private LocationManager mLocationManager;
        
        @Override
        public void onCreate() {
            mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
        
            mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
            if (checkPermission()) {
               mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, GPS_UPDATE_INTERVAL, MIN_DISTANCE, this);
            }
        
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                mGnssStatusCallback = new GnssStatus.Callback() {
                    @Override
                    public void onSatelliteStatusChanged(GnssStatus status) {
                        satelliteStatusChanged();
                    }
        
                    @Override
                    public void onFirstFix(int ttffMillis) {
                        gpsFixAcquired();
        
                    }
                };
                mLocationManager.registerGnssStatusCallback(mGnssStatusCallback);
            } else {
                mStatusListener = new GpsStatus.Listener() {
                    @Override
                    public void onGpsStatusChanged(int event) {
                        switch (event) {
                            case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
                                satelliteStatusChanged();
                                break;
                            case GpsStatus.GPS_EVENT_FIRST_FIX:
                                // Do something.
                                gpsFixAcquired();
                                break;
                        }
                    }
                };
                mLocationManager.addGpsStatusListener(mStatusListener);
            }
        }
        
        private void gpsFixAcquired() {
            // Do something.
            isGPSFix = true;
        }
        
        private void satelliteStatusChanged() {
            if (mLastLocation != null)
                isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < (GPS_UPDATE_INTERVAL * 2);
        
            if (isGPSFix) { // A fix has been acquired.
                // Do something.
            } else { // The fix has been lost.
                // Do something.
            }
        }
        
        @Override
        public void onLocationChanged(Location location) {
            if (location == null) return;
        
            mLastLocationMillis = SystemClock.elapsedRealtime();
        
            mLastLocation = location;
        }
        
        @Override
        public void onStatusChanged(String s, int i, Bundle bundle) {
        
        }
        
        @Override
        public void onProviderEnabled(String s) {
        
        }
        
        @Override
        public void onProviderDisabled(String s) {
        
        }
        

        注意:此答案是上述答案的组合。

        【讨论】:

        • 只要您信任其他作者,就可以为新作品或衍生作品获得自己的支持。这里的规则更关注人们抄袭其他人的答案并在 Stack Overflow 的其他地方使用它们以不诚实地吸引代表。既然您提到您已经建立在其他答案的基础上,我认为这很好。
        【解决方案8】:

        如果您只需要知道是否有修复,请检查 GPS 接收器提供的最后一个已知位置,并检查 .getTime() 值以了解该位置有多大。如果它足够新(比如......几秒钟),你就有一个修复。

           LocationManager lm = (LocationManager)context.getSystemService(LOCATION_SERVICE); 
           Location loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        
           // Get the time of the last fix
           long lastFixTimeMillis = loc.getTime(); 
        

        ... 最后将其与当前日期时间进行比较(以 UTC 为单位!)。如果它足够新,你有一个修复。

        我在我的应用程序中做到了这一点,到目前为止一切都很好。

        【讨论】:

        • +1 似乎值得一试,如果您立即想知道是否有修复。
        【解决方案9】:

        您可以尝试使用LocationManager.addGpsStatusListener 在 GPS 状态更改时获取更新。看起来 GPS_EVENT_STARTEDGPS_EVENT_STOPPED 可能就是您要查找的内容。

        【讨论】:

        • 状态监听器结合GPS_EVENT_FIRST_FIX 听起来更合适。
        【解决方案10】:

        我可能错了,但似乎人们似乎离题了

        我只需要知道屏幕顶部的 GPS 图标是否在闪烁(没有实际修复)

        这很容易用

        LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
        boolean gps_on = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
        

        要查看您是否有可靠的修复,事情会变得有点棘手:

        public class whatever extends Activity {
            LocationManager lm;
            Location loc;
            public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.main);        
                lm = (LocationManager) getSystemService(LOCATION_SERVICE);
                loc = null;
                request_updates();        
            }
        
            private void request_updates() {
                if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
                    // GPS is enabled on device so lets add a loopback for this locationmanager
                    lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,0, 0, locationListener);
                }      
            }
        
            LocationListener locationListener = new LocationListener() {
                public void onLocationChanged(Location location) {
                    // Each time the location is changed we assign loc
                    loc = location;
                }
        
                 // Need these even if they do nothing. Can't remember why.
                 public void onProviderDisabled(String arg0) {}
                 public void onProviderEnabled(String provider) {}
                 public void onStatusChanged(String provider, int status, Bundle extras) {}
            };
        

        现在只要你想看看你有没有修复?

        if (loc != null){
            // Our location has changed at least once
            blah.....
        }
        

        如果你想变得花哨,你总是可以使用 System.currentTimeMillis() 和 loc.getTime() 来设置超时

        从 2.1 起至少在 N1 上运行可靠。

        【讨论】:

        • 您的解决方案过于复杂。然而它做的很少。如果在 gps 解析了我的位置后我去地铁站导致 gps 无法定位怎么办?
        【解决方案11】:

        使用LocationManager,您可以在getBestProvider() 之后获得LastKnownLocation()。 这为您提供了一个 Location 对象,该对象具有以米为单位的 getAccuracy() 和以 UTC 毫秒为单位的 getTime() 方法

        这是否为您提供了足够的信息?

        或者也许您可以遍历 LocationProviders 并找出每个是否符合标准(ACCURACY_COARSE)

        【讨论】:

          【解决方案12】:

          这么多帖子...

          GpsStatus.Listener gpsListener = new GpsStatus.Listener() {
                                  public void onGpsStatusChanged(int event) {
                                      if( event == GpsStatus.GPS_EVENT_FIRST_FIX){
                                          showMessageDialog("GPS fixed");
                                      }
                                  }
                           };
          

          使用 addGpsListener 添加此代码... showMessageDialog ... 只显示带有字符串的标准对话窗口

          为我完美地完成了这项工作:) 非常感谢 :=) (对不起这篇文章,还不能投票)

          【讨论】:

          • 这只是第一个修复。进入隧道怎么办?
          【解决方案13】:

          如果您在修复丢失的那一刻不需要更新,您可以通过这种方式修改 Stephen Daye 的解决方案,您有一个方法可以检查修复是否仍然存在。

          因此,您可以在需要一些 GPS 数据并且不需要 GpsStatus.Listener 时检查它。

          “全局”变量是:

          private Location lastKnownLocation;
          private long lastKnownLocationTimeMillis = 0;
          private boolean isGpsFix = false;
          

          这是在“onLocationChanged()”中调用的方法,用于记住更新时间和当前位置。除此之外,它还会更新“isGpsFix”:

          private void handlePositionResults(Location location) {
                  if(location == null) return;
          
                  lastKnownLocation = location;
                  lastKnownLocationTimeMillis = SystemClock.elapsedRealtime();
          
                  checkGpsFix(); // optional
              }
          

          只要我需要知道是否有 GPS 定位,就会调用该方法:

          private boolean checkGpsFix(){
          
              if (SystemClock.elapsedRealtime() - lastKnownLocationTimeMillis < 3000) {
                  isGpsFix = true;
          
              } else {
                  isGpsFix = false;
                  lastKnownLocation = null;
              }
              return isGpsFix;
          }
          

          在我的实现中,我首先运行 checkGpsFix(),如果结果为真,我使用变量“lastKnownLocation”作为我的当前位置。

          【讨论】:

            【解决方案14】:

            我知道这有点晚了。但是,如果您想知道是否有修复,为什么不使用 NMEAListener。根据我的阅读,NMEAListener 会给你 NMEA 句子,然后你从中选择正确的句子。

            RMC 语句包含修复状态,A 表示 OK 或 V 表示警告。 GGA语句包含Fix Quality (0 invalid, 1 GPS or 2 DGPS)

            我无法为您提供任何 java 代码,因为我才刚刚开始使用 Android,但我已经在 C# 中为 Windows 应用程序创建了一个 GPS 库,我希望将其与 Xamarin 一起使用。我只是在寻找提供者信息时才看到这个帖子。

            从我目前所读到的关于 Location 对象的内容来看,我对 getAccuracy() 和 hasAccuracy() 之类的方法并不是很满意。我习惯于从 NMEA 语句中提取 HDOP 和 VDOP 值来确定我的修复的准确度。修复很常见,但 HDOP 很糟糕,这意味着您的水平精度根本不是很好。例如,坐在办公桌前用外部蓝牙 GPS 设备硬靠在窗户上进行调试,您很可能会得到修复,但 HDOP 和 VDOP 很差。将您的 GPS 设备放在外面的花盆或类似的地方,或在 GPS 上添加一个外部天线,您会立即获得良好的 HDOP 和 VDOP 值。

            【讨论】:

              【解决方案15】:

              也许最好的办法是创建一个 TimerTask,定期将接收到的 Location 设置为某个值(null?)。 如果 GPSListener 接收到新值,它将使用当前数据更新位置。

              我认为这将是一个可行的解决方案。

              【讨论】:

                【解决方案16】:

                你说你已经尝试过 onStatusChanged(),但这确实对我有用。

                这是我使用的方法(我让类自己处理 onStatusChanged):

                private void startLocationTracking() {
                    final int updateTime = 2000; // ms
                    final int updateDistance = 10; // meter
                    final Criteria criteria = new Criteria();
                    criteria.setCostAllowed(false);
                    criteria.setAccuracy(Criteria.ACCURACY_FINE);
                    final String p = locationManager.getBestProvider(criteria, true);
                    locationManager.requestLocationUpdates(p, updateTime, updateDistance,
                            this);
                }
                

                我处理 onStatusChanged 如下:

                void onStatusChanged(final String provider, final int status,
                        final Bundle extras) {
                    switch (status) {
                    case LocationProvider.OUT_OF_SERVICE:
                        if (location == null || location.getProvider().equals(provider)) {
                            statusString = "No Service";
                            location = null;
                        }
                        break;
                    case LocationProvider.TEMPORARILY_UNAVAILABLE:
                        if (location == null || location.getProvider().equals(provider)) {
                            statusString = "no fix";
                        }
                        break;
                    case LocationProvider.AVAILABLE:
                        statusString = "fix";
                        break;
                    }
                }
                

                注意 onProvider{Dis,En}abled() 方法是关于启用和禁用用户的 GPS 跟踪;不是你要找的。​​p>

                【讨论】:

                • 不幸的是,它通常不起作用。 onLocationChanged() 每秒被调用一次,但 onStatusChanged 根本不会被调用。有时我希望我可以只查询当前状态,而不是等待可能很长时间或永远不会出现的通知。
                • 对。在之前的回复之后,我自己学到了一些东西,其中之一是并非所有的 Android 平台都是一样的。我肯定在我的 HTC Hero 和 Archos 5 上都看到了对 onStatusChanged 的​​调用,但我并不感到惊讶,这并不适用于所有地方。计划 B 怎么样:您使用另一个答案中显示的 GPSStatusListener,并简单地查看是否有任何卫星为 usedInFix() 返回 true。根据我的经验,这最接近标准 GPS 图标的行为。 (您是否尝试过找到实现该标准图标的来源,顺便说一句?)
                【解决方案17】:

                设置检查修复的时间间隔不是一个好的选择。我注意到,如果您不移动,则不会调用 onLocationChanged.. 这是可以理解的,因为位置没有改变 :)

                更好的方法是例如:

                • 检查到最后收到位置的间隔(在 gpsStatusChanged 中)
                • 如果该间隔超过 15 秒,则设置变量:long_interval = true
                • 删除位置监听器并重新添加它,通常你会得到更新的位置 如果位置确实可用,如果没有 - 您可能丢失了位置
                • 在 onLocationChanged 中,您只需将 long_interval 设置为 false..

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-02-04
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-03-20
                  • 1970-01-01
                  • 2021-12-17
                  相关资源
                  最近更新 更多