Как разработчик SpeedView: GPS-спидометр для Android, я, должно быть, перепробовал все возможные решения этой проблемы, и все с тем же отрицательным результатом. Повторим, что не работает:
- onStatusChanged () не вызывается в Eclair и Froyo.
- Просто подсчитывать все доступные спутники, конечно, бесполезно.
- Проверка того, возвращает ли какой-либо из спутников true для usedInFix (), также не очень полезна. Система явно теряет исправление, но продолжает сообщать, что в ней все еще используются несколько спутников.
Итак, вот единственное рабочее решение, которое я нашел, и то, которое я использую в своем приложении. Допустим, у нас есть этот простой класс, который реализует 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) {
} else {
}
break;
case GpsStatus.GPS_EVENT_FIRST_FIX:
isGPSFix = true;
break;
}
}
}
Хорошо, теперь в onLocationChanged () мы добавляем следующее:
@Override
public void onLocationChanged(Location location) {
if (location == null) return;
mLastLocationMillis = SystemClock.elapsedRealtime();
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. Однако вы получите уведомление только при изменении состояния. Таким образом, невозможно определить текущее состояние, используя эти намерения.
источник
новый участник, поэтому, к сожалению, я не могу комментировать или голосовать за него, однако сообщение Стивена Дэйя выше было идеальным решением той же проблемы, с которой я искал помощи.
небольшое изменение в следующей строке:
isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;
кому:
isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < (GPS_UPDATE_INTERVAL * 2);
в основном, поскольку я создаю медленную игру, и мой интервал обновления уже установлен на 5 секунд, как только сигнал gps отсутствует на 10+ секунд, это подходящее время, чтобы что-то запустить.
Ура, приятель, потратил около 10 часов, пытаясь решить это решение, прежде чем нашел ваш пост :)
источник
Хорошо, давайте попробуем комбинацию всех ответов и обновлений на данный момент и сделаем что-то вроде этого:
ACCESS_FINE_LOCATION
разрешение в свой манифестLocationManager
GpsStatus.Listener
который реагирует наGPS_EVENT_SATELLITE_STATUS
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, как только они появятся. Если вы ничего не получаете, то, скорее всего, у вас нет решения. Вы можете комбинировать это со слушателем статуса выше, если хотите.После нескольких лет работы с GPS на Windows Mobile я понял, что концепция «потери» исправления GPS может быть субъективной. Чтобы просто послушать, что вам сообщает GPS, добавив NMEAListener и проанализировав предложение, вы узнаете, было ли исправление «действительным» или нет. См. Http://www.gpsinformation.org/dale/nmea.htm#GGA . К сожалению, у некоторых GPS это значение будет колебаться взад и вперед даже во время нормального режима работы в зоне «хорошего исправления».
Итак, другое решение - сравнить время в формате UTC местоположения GPS со временем телефона (преобразованным в UTC). Если между ними есть определенная разница во времени, можно предположить, что вы потеряли координаты GPS.
источник
столкнуться с подобной проблемой во время работы над моим проектом MSc, кажется, что ответ Дайе ошибочно сообщил «нет исправлений», пока устройство остается в статическом месте. Я немного изменил решение, которое, похоже, отлично работает для меня в статическом месте. Я не знаю, как это повлияет на батарею, поскольку это не моя главная проблема, но вот как я сделал это, повторно запросив обновления местоположения, когда время исправления истекло.
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
звуками похож на более близкого.Я могу ошибаться, но кажется, что люди уходят от темы
Это легко сделать с
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 ()
Работает надежно, по крайней мере, на N1 начиная с версии 2.1.
источник
С помощью LocationManager вы можете получитьLastKnownLocation () после того, как получитеBestProvider (). Это дает вам объект Location, который имеет методы getAccuracy () в метрах и getTime () в миллисекундах UTC.
Это дает вам достаточно информации?
Или, возможно, вы могли бы перебрать LocationProvider и выяснить, соответствует ли каждый из них Criteria (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 ... просто показывает стандартное диалоговое окно со строкой
отлично справился с работой :) Большое спасибо: =) (простите за этот пост, пока не могу проголосовать)
источник
Если вам не нужно обновление в тот момент, когда исправление потеряно, вы можете изменить решение Стивена Дейя таким образом, чтобы у вас был метод, который проверяет наличие исправления.
Таким образом, вы можете просто проверить его, когда вам нужны данные 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 содержит качество исправления (0 недействительно, 1 GPS или 2 DGPS)
Я не могу предложить вам никакого java-кода, поскольку я только начинаю работать с Android, но я сделал библиотеку GPS на C # для приложений Windows, которую я собираюсь использовать с Xamarin. Я наткнулся на эту ветку только потому, что искал информацию о провайдере.
Из того, что я читал до сих пор об объекте Location, мне не очень комфортно пользоваться такими методами, как getAccuracy () и hasAccuracy (). Я привык извлекать из предложений NMEA значения HDOP и VDOP, чтобы определить, насколько точны мои исправления. Довольно часто бывает исправление, но у вас паршивая HDOP, что означает, что ваша горизонтальная точность совсем не очень хорошая. Например, сидя за своим столом, отлаживая внешнее устройство Bluetooth 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-отслеживания пользователем; не то, что вы ищете.
источник
Установка временного интервала для проверки исправления - не лучший выбор .. я заметил, что onLocationChanged не вызывается, если вы не двигаетесь .. что понятно, так как местоположение не меняется :)
Лучше было бы, например:
источник