Как я могу проверить текущее состояние GPS-приемника? - PullRequest
87 голосов
/ 07 января 2010

Как я могу проверить текущее состояние GPS-приемника? Я уже проверил метод LocationListener onStatusChanged, но почему-то кажется, что он не работает или просто неправильная возможность.

По сути, мне просто нужно знать, мигает ли значок GPS вверху экрана (нет фактического исправления) или постоянно (исправление доступно).

Ответы [ 17 ]

146 голосов
/ 15 сентября 2010

Как разработчик SpeedView: GPS-спидометр для Android, я, должно быть, попробовал все возможные варианты решения этой проблемы, и все с одинаковым отрицательным результатом. Давайте еще раз повторим, что не работает:

  1. onStatusChanged () не вызывается для Eclair и Froyo.
  2. Простой подсчет всех доступных спутников, конечно, бесполезен.
  3. Проверка, возвращает ли какой-либо из спутников значение 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) { // 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, это близко к копированию его поведения. Надеюсь, это кому-нибудь поможет.

26 голосов
/ 03 ноября 2010

Значок 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. Тем не менее, вы будете уведомлены только при изменении состояния. Таким образом, невозможно определить текущее состояние, используя эти намерения.

18 голосов
/ 08 октября 2010

новый участник, поэтому, к сожалению, я не могу комментировать или голосовать, однако вышеприведенный пост Стивена Дея был идеальным решением той же проблемы, с которой я искал помощи.

небольшое изменение в следующей строке:

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

до:

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

в основном, когда я строю игру с медленным темпом, и мой интервал обновления уже установлен на 5 секунд, как только сигнал gps пропадет в течение 10+ секунд, это подходящее время для запуска чего-либо.

ура, приятель, потратил около 10 часов, пытаясь найти решение, прежде чем я нашел твой пост:)

14 голосов
/ 07 января 2010

Хорошо, давайте попробуем комбинацию всех ответов и обновлений и сделаем что-то вроде этого:

Слушатель 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 объект.

8 голосов
/ 06 августа 2010

После нескольких лет работы с GPS на Windows Mobile я понял, что концепция «потери» GPS-исправления может быть субъективной. Чтобы просто послушать, что говорит вам GPS, добавление NMEAListener и разбор предложения покажет вам, было ли исправление «действительным» или нет. См. http://www.gpsinformation.org/dale/nmea.htm#GGA. К сожалению, с некоторыми GPS это значение будет колебаться взад и вперед даже во время нормального хода работы в зоне «исправления».

Итак, другое решение - сравнить время UTC местоположения GPS с временем телефона (преобразованным в UTC). Если между ними существует определенная разница во времени, можно предположить, что вы потеряли позицию GPS.

7 голосов
/ 22 июля 2011

попали в аналогичную проблему, работая над моим проектом 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;
        }
    }
}
4 голосов
/ 04 сентября 2017

Хорошо, объединение каждого рабочего подхода приведет к этому (также имеет дело с устаревшим 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) {

}

Примечание: этот ответ является комбинацией ответов выше.

3 голосов
/ 28 мая 2012

Если вам просто нужно узнать, есть ли исправление, проверьте последнее известное местоположение, предоставленное приемником 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!). Если это достаточно недавно, у вас есть исправление.

Я делаю это в своем приложении и пока все хорошо.

2 голосов
/ 07 января 2010

Вы можете попробовать использовать LocationManager.addGpsStatusListener , чтобы получать обновления при изменении состояния GPS. Похоже, GPS_EVENT_STARTED и GPS_EVENT_STOPPED может быть тем, что вы ищете.

2 голосов
/ 11 мая 2011

Я могу ошибаться, но кажется, что люди, кажется, идут не по теме для

Мне просто нужно знать, мигает ли значок 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 ()

Надежно работает, по крайней мере, на N1 с 2.1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...