IT story

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

hot-time 2020. 9. 8. 22:00
반응형

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


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

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


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

  1. onStatusChanged ()가 Eclair 및 Froyo에서 호출되지 않습니다.
  2. 물론 사용 가능한 모든 위성을 세는 것은 쓸모가 없습니다.
  3. 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;

물론 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) {

}

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


수정 사항이 있는지 확인해야하는 경우 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_STARTEDGPS_EVENT_STOPPED를 찾으시는 것 같습니다 .


내가 틀렸을 수도 있지만 사람들이 주제에서 벗어나는 것 같습니다.

화면 상단의 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에서 안정적으로 작동합니다.


With LocationManager you can getLastKnownLocation() after you getBestProvider(). This gives you a Location object, which has the methods getAccuracy() in meters and getTime() in UTC milliseconds

Does this give you enough info?

Or perhaps you could iterate over the LocationProviders and find out if each one meetsCriteria( ACCURACY_COARSE )


so many posts...

GpsStatus.Listener gpsListener = new GpsStatus.Listener() {
                        public void onGpsStatusChanged(int event) {
                            if( event == GpsStatus.GPS_EVENT_FIRST_FIX){
                                showMessageDialog("GPS fixed");
                            }
                        }
                 };

adding this code, with addGpsListener... showMessageDialog ... just shows a standard dialog window with the string

did the job perfectly for me :) thanks a lot :=) (sry for this post, not yet able to vote)


If you do not need an update on the very instant the fix is lost, you can modify the solution of Stephen Daye in that way, that you have a method that checks if the fix is still present.

So you can just check it whenever you need some GPS data and and you don't need that GpsStatus.Listener.

The "global" variables are:

private Location lastKnownLocation;
private long lastKnownLocationTimeMillis = 0;
private boolean isGpsFix = false;

This is the method that is called within "onLocationChanged()" to remember the update time and the current location. Beside that it updates "isGpsFix":

private void handlePositionResults(Location location) {
        if(location == null) return;

        lastKnownLocation = location;
        lastKnownLocationTimeMillis = SystemClock.elapsedRealtime();

        checkGpsFix(); // optional
    }

That method is called whenever I need to know if there is a GPS fix:

private boolean checkGpsFix(){

    if (SystemClock.elapsedRealtime() - lastKnownLocationTimeMillis < 3000) {
        isGpsFix = true;

    } else {
        isGpsFix = false;
        lastKnownLocation = null;
    }
    return isGpsFix;
}

In my implementation I first run checkGpsFix() and if the result is true I use the variable "lastKnownLocation" as my current position.


I know this is a little late. However why not use the NMEAListener if you want to know if you have a fix. From what I've read, the NMEAListener will give you the NMEA sentences and from there you pick the correct sentence.

The RMC sentence contains the fix status which is either A for OK or V for warning. The GGA sentence contains the Fix Quality (0 invalid, 1 GPS or 2 DGPS)

I can't offer you any java code as I'm only just starting out with Android, but I have done a GPS library in C# for Windows apps, which I'm looking to use with Xamarin. I only came across this thread because I was looking for provider information.

From what I've read so far about the Location object I'm not all that comfortable about methods like getAccuracy() and hasAccuracy(). I'm used to extracting from the NMEA sentences HDOP and VDOP values to determine how accurate my fixes are. Its quite common to have a fix, but have a lousy HDOP which means your horizontal accuracy is not very good at all. For example sitting at your desk debugging with an external Bluetooth GPS device hard up against a window, you are quite likely to get a fix, but very poor HDOP and VDOP. Place your GPS device in a flower pot outside or something similar or add an external aerial to the GPS and immediately you get good HDOP and VDOP values.


Maybe it's the best possiblity to create a TimerTask that sets the received Location to a certain value (null?) regularly. If a new value is received by the GPSListener it will update the location with the current data.

I think that would be a working solution.


You say that you already tried onStatusChanged(), but that does work for me.

Here's the method I use (I let the class itself handle the 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);
}

And I handle the onStatusChanged as follows:

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

Note that the onProvider{Dis,En}abled() methods are about enabling and disabling GPS tracking by the user; not what you're looking for.


Setting time interval to check for fix is not a good choice.. i noticed that onLocationChanged is not called if you are not moving.. what is understandable since location is not changing :)

Better way would be for example:

  • check interval to last location received (in gpsStatusChanged)
  • if that interval is more than 15s set variable: long_interval = true
  • remove the location listener and add it again, usually then you get updated position if location really is available, if not - you probably lost location
  • in onLocationChanged you just set long_interval to false..

참고URL : https://stackoverflow.com/questions/2021176/how-can-i-check-the-current-status-of-the-gps-receiver

반응형