【发布时间】:2011-01-02 12:46:45
【问题描述】:
如何查看 GPS 接收器的当前状态?我已经检查了 LocationListener onStatusChanged 方法,但不知何故,它似乎不起作用,或者只是错误的可能性。
基本上我只需要知道屏幕顶部的 GPS 图标是闪烁(没有实际修复)还是稳定(修复可用)。
【问题讨论】:
如何查看 GPS 接收器的当前状态?我已经检查了 LocationListener onStatusChanged 方法,但不知何故,它似乎不起作用,或者只是错误的可能性。
基本上我只需要知道屏幕顶部的 GPS 图标是闪烁(没有实际修复)还是稳定(修复可用)。
【问题讨论】:
作为 SpeedView:Android 版 GPS 车速表的开发者,我一定尝试了所有可能的解决方案来解决这个问题,但结果都是一样的。让我们重申一下什么是行不通的:
这是我找到的唯一可行的解决方案,也是我在应用程序中实际使用的解决方案。假设我们有一个实现 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 图标的源代码,但这接近于复制它的行为。希望这对某人有所帮助。
【讨论】:
mLastLocationMillis 是由 GPS 以外的来源设置时,这不会中断吗?系统会声称 isGPSFix 是真的,但实际上它只是任何修复(可能来自电话网络)
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 状态的变化。但是,只有在状态发生变化时才会通知您。因此,无法使用这些意图确定当前状态。
【讨论】:
新成员很遗憾我无法发表评论或投票,但是 Stephen Daye 上面的帖子是解决我一直在寻求帮助的完全相同的问题的完美解决方案。
以下行的小改动:
isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;
到:
isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < (GPS_UPDATE_INTERVAL * 2);
基本上就像我在构建一个慢节奏的游戏并且我的更新间隔已经设置为 5 秒,一旦 gps 信号输出超过 10 秒,那就是触发某些东西的正确时间。
干杯伙伴,在我找到你的帖子之前花了大约 10 个小时试图解决这个解决方案 :)
【讨论】:
好的,让我们尝试结合目前所有的答案和更新,然后执行以下操作:
ACCESS_FINE_LOCATION 权限添加到您的清单中LocationManager
GPS_EVENT_SATELLITE_STATUS 作出反应的GpsStatus.Listener
LocationManager 注册监听器addGpsStatusListener
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 对象包含哪些信息的方法。
【讨论】:
GpsSatellite 对象中检索。
LocationManager.requestLocationUpdates 并将时间和距离设置设置为 0?这应该会在它们发生时立即向您发送 GPS 修复。如果您没有收到任何东西,那么您很可能没有修复程序。如果您愿意,可以将其与上面的状态监听器结合使用。
在 windows mobile 上使用 GPS 几年后,我意识到“丢失” GPS 定位的概念可能是主观的。要简单地听听 GPS 告诉您的内容,添加 NMEAListener 并解析句子将告诉您修复是否“有效”。见http://www.gpsinformation.org/dale/nmea.htm#GGA。不幸的是,对于某些 GPS,即使在“良好定位”区域的正常操作过程中,该值也会来回波动。
因此,另一种解决方案是将 GPS 位置的 UTC 时间与手机时间(转换为 UTC)进行比较。如果它们之间存在一定的时差,您可以假设您丢失了 GPS 位置。
【讨论】:
在处理我的 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;
}
}
}
【讨论】:
好吧,将所有工作方法放在一起会导致这种情况(同时处理已弃用的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) {
}
注意:此答案是上述答案的组合。
【讨论】:
如果您只需要知道是否有修复,请检查 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 为单位!)。如果它足够新,你有一个修复。
我在我的应用程序中做到了这一点,到目前为止一切都很好。
【讨论】:
您可以尝试使用LocationManager.addGpsStatusListener 在 GPS 状态更改时获取更新。看起来 GPS_EVENT_STARTED 和 GPS_EVENT_STOPPED 可能就是您要查找的内容。
【讨论】:
GPS_EVENT_FIRST_FIX 听起来更合适。
我可能错了,但似乎人们似乎离题了
我只需要知道屏幕顶部的 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 上运行可靠。
【讨论】:
使用LocationManager,您可以在getBestProvider() 之后获得LastKnownLocation()。 这为您提供了一个 Location 对象,该对象具有以米为单位的 getAccuracy() 和以 UTC 毫秒为单位的 getTime() 方法
这是否为您提供了足够的信息?
或者也许您可以遍历 LocationProviders 并找出每个是否符合标准(ACCURACY_COARSE)
【讨论】:
这么多帖子...
GpsStatus.Listener gpsListener = new GpsStatus.Listener() {
public void onGpsStatusChanged(int event) {
if( event == GpsStatus.GPS_EVENT_FIRST_FIX){
showMessageDialog("GPS fixed");
}
}
};
使用 addGpsListener 添加此代码... showMessageDialog ... 只显示带有字符串的标准对话窗口
为我完美地完成了这项工作:) 非常感谢 :=) (对不起这篇文章,还不能投票)
【讨论】:
如果您在修复丢失的那一刻不需要更新,您可以通过这种方式修改 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”作为我的当前位置。
【讨论】:
我知道这有点晚了。但是,如果您想知道是否有修复,为什么不使用 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 值。
【讨论】:
也许最好的办法是创建一个 TimerTask,定期将接收到的 Location 设置为某个值(null?)。 如果 GPSListener 接收到新值,它将使用当前数据更新位置。
我认为这将是一个可行的解决方案。
【讨论】:
你说你已经尝试过 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.. 这是可以理解的,因为位置没有改变 :)
更好的方法是例如:
【讨论】: