Android 如何查看 GPS 接收器的当前状态?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2021176/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 04:14:15  来源:igfitidea点击:

How can I check the current status of the GPS receiver?

androidgps

提问by nr1

How can I check the current status of the GPS receiver? I already checked the LocationListeneronStatusChangedmethod but somehow it seems that is not working, or just the wrong possibility.

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

Basically I just need to know if the GPS icon at the top of the screen is blinking (no actual fix) or solid (fix is available).

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

回答by soundmaven

As a developer of SpeedView: GPS speedometer for Android, I must have tried every possible solution to this problem, all with the same negative result. Let's reiterate what doesn't work:

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

  1. onStatusChanged() isn't getting called on Eclair and Froyo.
  2. Simply counting all available satellites is, of course, useless.
  3. Checking if any of the satellites return true for usedInFix() isn't very helpful also. The system clearly loses the fix but keeps reporting that there are still several sats that are used in it.
  1. Eclair 和 Froyo 没有调用 onStatusChanged()。
  2. 当然,简单地计算所有可用的卫星是没有用的。
  3. 检查是否有任何卫星为 usedInFix() 返回 true 也不是很有帮助。系统显然丢失了修复,但一直报告其中仍有几个卫星在使用。

So here's the only working solution I found, and the one that I actually use in my app. Let's say we have this simple class that implements the GpsStatus.Listener:

所以这是我找到的唯一可行的解​​决方案,也是我在应用程序中实际使用的解决方案。假设我们有一个实现 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;
        }
    }
}

OK, now in onLocationChanged() we add the following:

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

@Override
public void onLocationChanged(Location location) {
    if (location == null) return;

    mLastLocationMillis = SystemClock.elapsedRealtime();

    // Do something.

    mLastLocation = location;
}

And that's it. Basically, this is the line that does it all:

就是这样。基本上,这是完成这一切的行:

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

You can tweak the millis value of course, but I'd suggest to set it around 3-5 seconds.

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

This actually works and although I haven't looked at the source code that draws the native GPS icon, this comes close to replicating its behaviour. Hope this helps someone.

这实际上是有效的,虽然我还没有查看绘制本地 GPS 图标的源代码,但这接近于复制其行为。希望这可以帮助某人。

回答by sast

The GPS icon seems to change its state according to received broadcast intents. You can change its state yourself with the following code samples:

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

Notify that the GPS has been enabled:

通知 GPS 已启用:

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

Notify that the GPS is receiving fixes:

通知 GPS 正在接收修复:

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

Notify that the GPS is no longer receiving fixes:

通知 GPS 不再接收修复:

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

Notify that the GPS has been disabled:

通知 GPS 已被禁用:

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

Example code to register receiver to the intents:

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

// 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);

By receiving these broadcast intents you can notice the changes in GPS status. However, you will be notified only when the state changes. Thus it is not possible to determine the current state using these intents.

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

回答by chich

new member so unfortunately im unable to comment or vote up, however Stephen Daye's post above was the perfect solution to the exact same problem that i've been looking for help with.

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

a small alteration to the following line:

对以下行的小改动:

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

to:

到:

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

basically as im building a slow paced game and my update interval is already set to 5 seconds, once the gps signal is out for 10+ seconds, thats the right time to trigger off something.

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

cheers mate, spent about 10 hours trying to solve this solution before i found your post :)

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

回答by Christopher Orr

Ok, so let's try a combination of all the answers and updates so far and do something like this:

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

The GPS listener could be something like this:

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
        }
    }
}

The APIs are a bit unclear about when and what GPS and satellite information is given, but I think an idea would be to look at how many satellites are available. If it's below three, then you can't have a fix. If it's more, then you should have a fix.

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

Trial and error is probably the way to go to determine how often Android reports satellite info, and what info each GpsSatelliteobject contains.

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

回答by Justin Breitfeller

After a few years of working with GPS on windows mobile, I realized that the concept of "losing" a GPS fix can be subjective. To simply listen to what the GPS tells you, adding a NMEAListener and parsing the sentence will tell you whether the fix was "valid" or not. See http://www.gpsinformation.org/dale/nmea.htm#GGA. Unfortunately with some GPSes this value will fluctuate back and forth even during the normal course of operation in a "good fix" area.

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

So, the other solution is to compare the UTC time of the GPS location against the phone's time (converted to UTC). If they are a certain time difference apart, you can assume you lost the GPS position.

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

回答by Jeffery Lee

get into similar problem while working on my MSc project, it seems that Daye's answer mistakenly reported "no fix" while the device stays in a static location. I've modified the solution just a little bit which seems to work fine for me in a static location. I don't how would it affect the battery as it is not my main concern, but here's how i did it by re-requesting location updates when a fix has timed out.

在处理我的 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;
        }
    }
}

回答by Gregory Stein

Well, putting together every working approach will result in this (also dealing with deprecated GpsStatus.Listener):

好吧,将所有工作方法放在一起会导致这个(也处理 deprecated 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) {

}

Note: this answer is a combination of the answers above.

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

回答by Adan

If you just need to know if there's a fix, then check for the last known location provided by the GPS receiver and check the .getTime() value to know how old is that. If it's recent enough (like... a few seconds) you have a fix.

如果您只需要知道是否有修复,则检查 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(); 

... and finally compare that to current date time (In UTC!). If it's recent enough you have a fix.

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

I do that in my app and so far so good.

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

回答by regomodo

I may be wrong but it seems people seem to be going way off-topic for

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

i just need to know if the gps icon at the top of the screen is blinking (no actual fix)

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

That is easily done with

这很容易做到

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

To see if you have a solid fix, things get a little trickier:

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

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

Now whenever you want to see if you have fix?

现在什么时候你想看看你有没有修复?

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

If you want to be fancy you can always have a timeout using System.currentTimeMillis() and loc.getTime()

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

Works reliably, at least on an N1 since 2.1.

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

回答by Erich Douglass

You could try using LocationManager.addGpsStatusListenerto get updated when the GPS status changes. It looks like GPS_EVENT_STARTEDand GPS_EVENT_STOPPEDmight be what you're looking for.

您可以尝试使用LocationManager.addGpsStatusListener在 GPS 状态更改时进行更新。看起来GPS_EVENT_STARTEDGPS_EVENT_STOPPED可能正是您要找的。