web-dev-qa-db-ja.com

GPS受信機の現在のステータスを確認するにはどうすればよいですか?

GPS受信機の現在のステータスを確認するにはどうすればよいですか?私はすでにLocationListeneronStatusChanged メソッドをチェックしましたが、どういうわけか機能していないか、単に間違っている可能性があります。

基本的には、画面上部のGPSアイコンが点滅している(実際に修正されていない)か、点灯している(修正が利用できる)かを知るだけです。

88
nr1

SpeedView:Android向けGPS速度計の開発者として、この問題に対するすべての可能な解決策を試してみたに違いありません。うまくいかないことを繰り返してみましょう:

  1. onStatusChanged()は、EclairとFroyoで呼び出されません。
  2. もちろん、利用可能なすべての衛星を数えるだけでは役に立ちません。
  3. いずれかのサテライトがusedInFix()に対してtrueを返すかどうかを確認することもあまり役に立ちません。システムは明らかに修正を失いますが、まだいくつかの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;
        }
    }
}

OK、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アイコンを描画するソースコードを見たことはありませんが、これはその動作を再現することに近づいています。これが誰かを助けることを願っています。

146
soundmaven

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ステータスの変化に気づくことができます。ただし、状態が変化したときにのみ通知されます。したがって、これらの意図を使用して現在の状態を判断することはできません。

26
sast

残念ながら新しいメンバーはコメントも投票もできませんが、上記のStephen Dayeの投稿は、私が助けを求めているのとまったく同じ問題に対する完璧な解決策でした。

次の行の小さな変更:

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

に:

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

基本的には、ペースの遅いゲームを構築していて、更新間隔が既に5秒に設定されているため、gps信号が10秒以上出たら、それが適切なタイミングでトリガーされます。

あなたの投稿を見つける前に、このソリューションを解決しようとして約10時間費やしました

18
chich

それでは、これまでのすべての回答と更新の組み合わせを試して、次のようなことをしてみましょう。

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オブジェクトに含まれる情報を判断する方法です。

14
Christopher Orr

Windows MobileでGPSを数年間使用した後、GPSの修正を「失う」という概念は主観的であることに気付きました。 GPSが示す内容を単純に聞くために、NMEAListenerを追加して文を解析すると、修正が「有効」であったかどうかがわかります。 http://www.gpsinformation.org/dale/nmea.htm#GGA を参照してください。残念なことに、一部のGPSでは、この値は「正常な修正」エリアでの通常の運用中であっても前後に変動します。

そのため、もう1つの解決策は、GPSロケーションのUTC時間を電話の時間(UTCに変換)と比較することです。一定の時間差がある場合は、GPS位置を失ったとみなすことができます。

8

私の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;
        }
    }
}
7
Jeffery Lee

さて、すべての作業アプローチをまとめると、これが発生します(非推奨の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) {

}

注:この回答は、上記の回答の組み合わせです。

4
Gregory Stein

修正があるかどうかを知る必要がある場合は、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!)と比較します。それが十分に最近の場合、修正があります。

私は自分のアプリでそれを行っており、これまでのところはこれでいいです。

3
Adan

LocationManager.addGpsStatusListener を使用して、GPSステータスが変更されたときに更新されるようにすることができます。 GPS_EVENT_STARTED および GPS_EVENT_STOPPED のように見えます。

2
Erich Douglass

私は間違っているかもしれませんが、人々はトピックから外れているようです

画面上部の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で確実に動作します。

2
regomodo

LocationManagerを使用すると、getBestProvider()の後にgetLastKnownLocation()を使用できます。これは、メートル単位のgetAccuracy()メソッドとUTCミリ秒単位のgetTime()メソッドを持つLocationオブジェクトを提供します

これで十分な情報が得られますか?

または、LocationProvidersを反復処理し、それぞれがCriteria(ACCURACY_COARSE)を満たしているかどうかを調べることができます

1
Mark Borgerding

たくさんの投稿...

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

addGpsListener ... showMessageDialogを使用してこのコードを追加すると、文字列を含む標準のダイアログウィンドウが表示されます。

私のために完璧に仕事をしてくれました:)どうもありがとう:=)(この投稿をお願いします、まだ投票できません)

1
cV2

私はこれが少し遅いことを知っています。ただし、修正があるかどうかを知りたい場合は、NMEAListenerを使用しないでください。私が読んだことから、NMEAListenerはNMEAセンテンスを提供し、そこから正しいセンテンスを選択します。

RMC文には修正ステータスが含まれており、OKの場合はA、警告の場合はVです。 GGA文には修正品質(無効0、1 GPSまたは2 DGPS)が含まれています

Androidで始めたばかりなのでJavaコードを提供することはできませんが、Xamarinで使用したいWindowsアプリ用のC#でGPSライブラリを作成しました。プロバイダー情報を探していたため、このスレッドに出くわしただけです。

Locationオブジェクトについてこれまでに読んだことから、g​​etAccuracy()やhasAccuracy()などのメソッドについてはそれほど快適ではありません。私はNMEAセンテンスからHDOPとVDOPの値を抽出して、修正の精度を判断することに慣れています。修正することは非常に一般的ですが、HDOPが粗末であるため、水平方向の精度がまったく良くありません。たとえば、外部のBluetooth GPSデバイスを使用してデスクでデバッグを行うと、ハードディスクがウィンドウにぶつかる可能性が高くなりますが、HDOPとVDOPは非常に貧弱です。 GPSデバイスを外の植木鉢などに置くか、GPSに外部アンテナを追加すると、すぐにHDOPとVDOPの値が良好になります。

1
user2153142

修正が失われた瞬間に更新が必要ない場合は、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()を実行し、結果がtrueの場合、変数「lastKnownLocation」を現在の位置として使用します。

1

修正をチェックする時間間隔を設定するのは良い選択ではありません。移動していない場合はonLocationChangedが呼び出されないことに気付きました。場所は変わっていません:)

より良い方法は、たとえば次のようになります:

  • 最後に受信した場所までの間隔をチェックします(gpsStatusChangedで)
  • その間隔が15秒を超える場合、変数を設定します:long_interval = true
  • ロケーションリスナーを削除して再度追加します。通常、ロケーションが実際に使用可能な場合は更新された位置を取得し、そうでない場合はおそらくロケーションを失います
  • onLocationChangedでは、long_intervalをfalseに設定しただけです。
0
Hardy

あなたはすでに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追跡の有効化および無効化に関するものであることに注意してください。あなたが探しているものではありません。

0
CvR

たぶん、受信したLocationを特定の値(null?)に定期的に設定するTimerTaskを作成するのが最良の可能性です。 GPSListenerが新しい値を受け取ると、現在のデータで場所を更新します。

それが有効な解決策になると思います。

0
nr1