[android] GPS 수신기의 현재 상태를 어떻게 확인할 수 있습니까?

GPS 수신기의 현재 상태를 어떻게 확인할 수 있습니까? 나는 이미 LocationListener onStatusChanged방법을 확인 했지만 어떻게 든 작동하지 않거나 잘못된 가능성이있는 것 같습니다.

기본적으로 화면 상단의 GPS 아이콘이 깜박이는지 (실제 수정 없음) 또는 계속 켜져 있는지 (수정 가능) 알면됩니다.



답변

SpeedView : Android 용 GPS 속도계 개발자로서 저는이 문제에 대해 가능한 모든 해결책을 시도했지만 모두 동일한 부정적인 결과를 보였을 것입니다. 작동하지 않는 것을 반복 해 보겠습니다.

  1. onStatusChanged ()가 Eclair 및 Froyo에서 호출되지 않습니다.
  2. 물론 사용 가능한 모든 위성을 세는 것은 쓸모가 없습니다.
  3. usedInFix ()에 대해 참을 반환하는 위성이 있는지 확인하는 것도 그다지 도움이되지 않습니다. 시스템은 분명히 수정 사항을 잃었지만 여전히 사용되는 여러 개의 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;

물론 millis 값을 조정할 수 있지만 3 ~ 5 초 정도 설정하는 것이 좋습니다.

이것은 실제로 작동하며 네이티브 GPS 아이콘을 그리는 소스 코드를 보지는 않았지만 동작을 복제하는 것과 비슷합니다. 이것이 누군가를 돕기를 바랍니다.


답변

수신 된 방송 의도에 따라 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 시간을 보냈습니다 🙂


답변

좋습니다. 지금까지의 모든 답변과 업데이트를 조합하여 다음과 같이 해보겠습니다.

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 및 위성 정보가 제공되는지에 대해 약간 불분명하지만 몇 개의 위성을 사용할 수 있는지 살펴 보는 것이 아이디어라고 생각합니다. 3 미만이면 고칠 수 없습니다. 더 많으면 수정해야합니다.

시행 착오는 Android가 위성 정보를보고하는 빈도와 각 GpsSatellite개체에 포함 된 정보를 확인하는 방법 일 것 입니다.


답변

Windows 모바일에서 몇 년 동안 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;
        }
    }
}


답변

글쎄, 모든 작업 접근 방식을 통합하면 다음과 같은 결과가 나타납니다 (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) {

}

참고 :이 답변은 위 답변의 조합입니다.