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


90

GPSレシーバーの現在のステータスを確認するにはどうすればよいですか?私はすでにLocationListener onStatusChanged方法をチェックしましたが、どういうわけかそれは機能していないか、単に間違った可能性があるようです。

基本的に、画面の上部にあるGPSアイコンが点滅している(実際の修正はない)か、点灯している(修正が利用可能)かを知る必要があります。

回答:


150

SpeedView:Android向けGPSスピードメーターの開発者として、私はこの問題に対するすべての可能な解決策を試したに違いありません。うまくいかないことを繰り返しましょう:

  1. onStatusChanged()がEclairとFroyoで呼び出されていません。
  2. もちろん、利用可能なすべての衛星を数えるだけでは無意味です。
  3. usedInFix()でサテライトのいずれかがtrueを返すかどうかを確認することもあまり役に立ちません。システムは明らかに修正を失いますが、使用されている状態がまだいくつかあることを報告し続けます。

だから、ここで私が見つけた唯一の実用的なソリューションと、私が実際に自分のアプリで使用しているものを紹介します。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アイコンを描画するソースコードを見たことはありませんが、これは動作を再現するところです。これが誰かを助けることを願っています。


こんにちは、この例のように、利用可能な衛星を数えることがなぜ役に立たないのでしょうか。見つかった衛星の数が0の場合、接続がないことを意味しますか、それとも間違っていますか?groups.google.com/group/android-developers/browse_thread/thread/...
per_jansson

3
こんにちは、スティーブン。isGPSFixが機能する理由を説明してください。ありがとう、ニック
nickfox

ちなみに、ICSでは、システムがGPSの修正が失われたことを報告し始めるまでの時間が長くなっていることに気づきました。少なくとも4.0.3では、正確に10秒です。
soundmaven

うまく機能し、ICSの3-5とは対照的に10秒を使用することも非常にうまく機能します。幸い、修正は私のアプリに必要な機能ではありませんが、それを知ることができるのは良いことです。ありがとう。
トム

1
しかしmLastLocationMillis、GPS以外のソースによって設定された場合、これは壊れませんか?システムだろう主張よりもisGPSFix真実であるが、現実にはそれだけで任意の修正(電話ネットワークから多分1)
パトリック・

25

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


システムから保護されたブロードキャストであると思われるため、アプリケーションからブロードキャストを送信する方法を知りません。そのインテントを送信するアプリはすべてクラッシュするはずです。
JoxTraex 2016

答えを書いた6年前に送ることができました。どうやら彼らはそれ以来システムにいくらかの保護を加えてきた。
sast

これらのインテントを使用して、他のアプリがGPSを使用していたことを通知していました。私はNougatから始めて、あなたはこれらの意図をもう聞くことさえできないか、あるいはそれが変わったのだと思います!自分のアプリで位置情報を聞きたくありません。誰か他のアイデアがありますか?
Flyview '12

はい、クラッシュしました:05-14 10:25:24.113 17344-17344 / xxx.yyy.zzz.debug E / AndroidRuntime:FATAL EXCEPTION:main Process:xxx.yyy.zzz.debug、PID:17344 java。 lang.SecurityException:Permission Denial:ブロードキャストの送信は許可されていませんandroid = location.GPS_FIX_CHANGE from pid = 17344、uid = 10416
unlimited101

19

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

次の行の小さな変更:

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

に:

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

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

乾杯の仲間、私があなたの投稿を見つける前にこの解決策を解決するために約10時間を費やしました:)


14

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

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オブジェクトに含まれる情報を特定するための方法です。


利用可能な衛星を数える際の問題は、たとえ5つの衛星が見えていても、常に修正が可能であるということではありません。(「それ以上の場合は、修正が必要です」と書いて正しいと述べました)
nr1

確かに。修正を構成するために必要な情報、またはGpsSatelliteオブジェクトからどのように/どのようにしてこれを取得できるかについては、もうわかりません。
Christopher Orr

別の考え..あなたはあなたの質問でこれについて言及していませんLocationManager.requestLocationUpdatesが、時間と距離の設定を0に設定して使用したことはありますか?GPSの修正が行われるとすぐに送信されます。何も受け取っていない場合は、おそらく修正されていません。必要に応じて、これを上記のステータスリスナーと組み合わせることができます。
Christopher Orr

1
「sats」を繰り返してGpsSatelliteでusedInFix()をチェックしているのでしょうか?
DeliriumTremens

8

Windows MobileでGPSを数年使用した後、GPSフィックスを「失う」という概念は主観的である可能性があることに気付きました。GPSからの通知を単純に聞くには、NMEAListenerを追加して文を解析すると、修正が「有効」であったかどうかがわかります。http://www.gpsinformation.org/dale/nmea.htm#GGAを参照してください。残念ながら、一部のGPSでは、この値は、「良好な修正」領域での通常の動作コースの間でも前後に変動します。

したがって、他の解決策は、GPS位置のUTC時間と電話の時間(UTCに変換)を比較することです。一定の時間差がある場合は、GPS位置を失ったと考えられます。


時間比較方法を説明していただけませんか?Stephen Dayeの回答で、彼は最後の修正が行われたときと最新のGPS_EVENT_SATELLITE_STATUSイベントの間の時間差を比較しました...それが何を測定しているのかわかりません。
Rokey Geの

7

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

5

まあ、すべての実用的なアプローチをまとめると、次のようになります(非推奨のも扱います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) {

}

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


1
あなたが他の著者を信用している限り、新しいまたは派生した作品のためにあなた自身の賛成票を得ることは問題ありません。ここでのルールは、担当者を不正に引き付けるために、他の人々の回答を盗用し、Stack Overflowの他の場所でそれらを使用する人々についてより懸念しています。他の回答に基づいて作成したとおっしゃっていたので、これで結構です。
2017年

3

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

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


修正があるかどうかをすぐに知りたい場合は、+ 1を試す価値があるようです。
AgentKnopf 2012


2

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

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


3
あなたのソリューションは、それが何をするのかについて複雑すぎます。ただし、ほとんど機能しません。gpsが私の場所を解決した後、私が地下鉄の駅に行って、gpsが修正を失うとどうなりますか?
meandre 2013

1

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

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

または、LocationProvidersを反復処理して、それぞれがmeetsCriteria(ACCURACY_COARSE)かどうかを確認することもできます


1

非常に多くの投稿...

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

このコードをaddGpsListenerで追加します... showMessageDialog ...は、標準のダイアログウィンドウに文字列を表示します

私のために完全に仕事をしました:)どうもありがとう:=)(この投稿のために申し訳ありませんが、まだ投票できません)


これは最初の修正にすぎません。トンネルに入るとどうなりますか?
Leos Literak

1

修正が失われた瞬間に更新が必要ない場合、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

私はこれが少し遅れていることを知っています。ただし、修正があるかどうかを知りたい場合は、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値が得られます。


0

受信したLocationを定期的に特定の値(null?)に設定するTimerTaskを作成するのが最善の方法かもしれません。GPSListenerが新しい値を受信すると、現在のデータで位置が更新されます。

私はそれが実用的な解決策になると思います。


0

あなたはすでに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()は1秒に1回呼び出されますが、onStatusChangedはまったく呼び出されません。時々届かない通知を待つのではなく、現在のステータスを照会したい場合があります。
Edward Falk

2
正しい。その前の返事の後で私はいくつかのことを学びました、そして一つはすべてのAndroidプラットフォームが同じように作られているわけではないということです。私のHTC HeroとArchos 5の両方でonStatusChangedへの呼び出しが確実に見られますが、どこでも機能しないわけではありません。プランBはどうでしょうか。別の回答に示されているGPSStatusListenerを使用し、衛星のいずれかがusedInFix()に対してtrueを返すかどうかを確認します。私の経験では、これは標準のGPSアイコンの動作に最も近いものです。(その標準アイコン、BTWを実装するソースを見つけようとしましたか?)
CvR 2010

0

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

より良い方法は、例えば:

  • 最後に受信した位置までの間隔を確認(gpsStatusChanged内)
  • その間隔が15秒を超える場合は、変数を設定します:long_interval = true
  • 場所リスナーを削除して再度追加します。通常、場所が実際に利用可能な場合は更新された位置を取得し、そうでない場合はおそらく場所を失います
  • onLocationChangedでは、long_intervalをfalseに設定するだけです。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.