Android:LocationManagerとGoogle Play開発者サービス


151

ユーザーの現在位置を取得することを中心としたアプリを作成し、Google Places APIを介してユーザーに近い興味のあるポイント(バー、レストランなど)を見つけたいと考えています

Webを開始する場所を検索すると、LocationManagerクラスを使用するいくつかのチュートリアルと、ユーザーの場所を見つけるためにGoogle Play開発者サービスを使用するいくつかのチュートリアルに出くわしました。

一見すると、どちらも同じことを行いますが、これに慣れていないので少し混乱し、どの方法が自分のニーズに最適であるかわかりません。だから、私はあなたに尋ねたいです:

ロケーションがある場合、これら2つの場所を見つける方法の違いは何ですか?


回答:


319

Androidでのユーザーの場所

Androidでのユーザーの現在地の取得は、iOSの場合よりも簡単ではありません。混乱を始めるには、2つのまったく異なる方法があります。1つ目はのAndroid APIを使用してandroid.location.LocationListenerおり、2つ目はGoogle Play Services APIを使用していますcom.google.android.gms.location.LocationListener。両方を見てみましょう。

  1. AndroidのLocation API

    Androidの位置情報APIは、3つの異なるプロバイダーを使用して位置情報を取得します-

    • LocationManager.GPS_PROVIDER—このプロバイダーは、衛星を使用して位置を特定します。条件によっては、このプロバイダーが位置情報フィックスを返すまでに時間がかかる場合があります。
    • LocationManager.NETWORK_PROVIDER—このプロバイダーは、セルタワーとWiFiアクセスポイントの可用性に基づいて場所を決定します。結果はネットワークルックアップによって取得されます。
    • LocationManager.PASSIVE_PROVIDER—このプロバイダーは、他のプロバイダーによって生成された場所を返します。他のアプリケーションまたはサービスが実際に位置を要求することなく、それらを要求すると、位置の更新を受動的に受け取ります。

その要点はLocationManager、システムからオブジェクトを取得し、を実装してLocationListener、でを呼び出すrequestLocationUpdatesことLocationManagerです。

ここにコードスニペットがあります:

    LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener() {
    public void onLocationChanged(Location location) {
      // Called when a new location is found by the network location provider.
      makeUseOfNewLocation(location);
    }

    public void onStatusChanged(String provider, int status, Bundle extras) {}

    public void onProviderEnabled(String provider) {}

    public void onProviderDisabled(String provider) {}
  };

// Register the listener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);

ロケーション戦略に関するGoogleのAPIガイドコードをかなりうまく説明しています。ただし、ほとんどの場合、代わりにGoogle Location Services APIを使用すると、バッテリーのパフォーマンスが向上し、より適切な精度が得られるとも述べています。今混乱が始まります!

  1. Googleの位置情報サービスAPI

Googleの位置情報サービスAPIは、Google Play Services APKの一部です(設定方法はこちら)。これらはAndroidのAPIの上に構築されています。これらのAPIは、上記のプロバイダーの代わりに「融合ロケーションプロバイダー」を提供します。このプロバイダーは、精度、バッテリー使用量などに基づいて、使用する基盤となるプロバイダーを自動的に選択します。システム全体のサービスから位置情報を取得し続けるため、高速です。また、ジオフェンシングなどのより高度な機能を使用できます。

Googleの位置情報サービスを使用するには、アプリがに接続する必要がありGooglePlayServicesClientます。クライアントに接続するには、アクティビティ(またはフラグメントなど)を実装GooglePlayServicesClient.ConnectionCallbacksしてGooglePlayServicesClient.OnConnectionFailedListenerインターフェースする必要があります。これがサンプルコードです:

    public class MyActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener {
    LocationClient locationClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        locationClient = new LocationClient(this, this, this);
    }

    @Override
    public void onConnected(Bundle bundle) {
    Location location = locationClient.getLastLocation() ;
        Toast.makeText(this, "Connected to Google Play Services", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onDisconnected() {
    Toast.makeText(this, "Connected from Google Play Services.", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        // code to handle failed connection
        // this code can be found here — http://developer.android.com/training/location/retrieve-current.html 
    }
  • なぜlocationClient.getLastLocation()nullなのですか?

locationClient.getLastLocation()クライアントからの最後の既知の位置を取得します。ただし、フューズドロケーションプロバイダーは、少なくとも1つのクライアントが接続されている場合にのみバックグラウンドのロケーションを維持します。最初のクライアントが接続すると、すぐに場所を取得しようとします。アクティビティが接続する最初のクライアントgetLastLocation()でありonConnected()、すぐにに電話をかけた場合、最初の場所に到着するのに十分な時間ではない可能性があります。これにより、locationになりnullます。

この問題を解決するには、プロバイダーが場所を取得するまで(無期限に)待機してからを呼び出すgetLastLocation()必要があります。別の(より良い)オプションは、com.google.android.gms.location.LocationListener定期的な位置情報の更新を受信するようにインターフェイスを実装することです(そして、最初の更新を取得したらそれをオフにします)。

    public class MyActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener {
    // . . . . . . . . more stuff here 
    LocationRequest locationRequest;
    LocationClient locationClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // . . . . other initialization code
        locationClient = new LocationClient(this, this, this);
    locationRequest = new LocationRequest();
    // Use high accuracy
    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        // Set the update interval to 5 seconds
    locationRequest.setInterval(UPDATE_INTERVAL);
        // Set the fastest update interval to 1 second
    locationRequest.setFastestInterval(FASTEST_INTERVAL);
    }
    // . . . . . . . . other methods 
    @Override
    public void onConnected(Bundle bundle) {
        Location location = locationClient.getLastLocation();
        if (location == null)
            locationClient.requestLocationUpdates(locationRequest, this);
        else
            Toast.makeText(getActivity(), "Location: " + location.getLatitude() + ", " + location.getLongitude(), Toast.LENGTH_SHORT).show();
    }
    // . . . . . . . . other methods
    @Override
    public void onLocationChanged(Location location) {
        locationClient.removeLocationUpdates(this);
        // Use the location here!!!
    }

このコードでは、クライアントが最後の場所(内onConnected)をすでに持っているかどうかを確認しています。そうでない場合は、位置情報の更新を要求しonLocationChanged()、更新を取得したらすぐに(コールバックで)要求をオフにします。

注意locationClient.requestLocationUpdates(locationRequest, this);の内側にある必要がありonConnected、コールバック、または他のあなたが得るIllegalStateExceptionあなたがGoogle Playのサービスクライアントに接続することなく、場所については、要求しようとするため。

  • ユーザーが位置情報サービスを無効にしました

多くの場合、ユーザーは位置情報サービスを無効にします(バッテリーやプライバシー上の理由から)。このような場合でも、上記のコードは位置情報の更新を要求しますが、onLocationChanged呼び出されることはありません。ユーザーが位置情報サービスを無効にしているかどうかを確認することで、要求を停止できます。

アプリで位置情報サービスを有効にする必要がある場合は、メッセージまたはトーストを表示する必要があります。残念ながら、ユーザーがGoogleの位置情報サービスAPIで位置情報サービスを無効にしているかどうかを確認する方法はありません。そのためには、AndroidのAPIに戻る必要があります。

あなたのonCreate方法では:

    LocationManager manager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && !manager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
    locationEnabled = false;
    Toast.makeText(getActivity(), "Enable location services for accurate data", Toast.LENGTH_SHORT).show();
}
else locationEnabled = true;

次のようにメソッドでlocationEnabledフラグを使用しますonConnected

    if (location != null) {
    Toast.makeText(getActivity(), "Location: " + location.getLatitude() + ", " + location.getLongitude(), Toast.LENGTH_SHORT).show();
}
else if (location == null && locationEnabled) {
    locationClient.requestLocationUpdates(locationRequest, this);
}

更新

ドキュメントが更新され、LocationClientが削除され、APIがダイアログからのワンクリックでGPSを有効にすることをサポートします。

task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
    // All location settings are satisfied. The client can initialize
    // location requests here.
    // ...
}
});

task.addOnFailureListener(this, new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception e) {
        if (e instanceof ResolvableApiException) {
            // Location settings are not satisfied, but this can be fixed
            // by showing the user a dialog.
            try {
                // Show the dialog by calling startResolutionForResult(),
                // and check the result in onActivityResult().
                ResolvableApiException resolvable = (ResolvableApiException) e;
                resolvable.startResolutionForResult(MainActivity.this,
                        REQUEST_CHECK_SETTINGS);
            } catch (IntentSender.SendIntentException sendEx) {
                // Ignore the error.
            }
        }
    }
});

リンクhttps://developer.android.com/training/location/change-location-settings#prompt

新しいロケーションクライアント:FusedLocationProviderClient

  private FusedLocationProviderClient fusedLocationClient;

@Override
protected void onCreate(Bundle savedInstanceState) {
    fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
}

ロケーションタスクを実行する前に、https://developer.android.com/training/locationを確認することをお勧めします


9
を使用SettingsApi.checkLocationSettings()して、ユーザーが位置情報サービスを有効にしているかどうかを確認できます(こちらを参照してください:developers.google.com/android/reference/com/google/android/gms/…)。
kaolick 2015年

3
LocationClientはもう存在しません。ロケーションの更新された明確なガイドについては、この記事を確認してください:blog.teamtreehouse.com/beginners-guide-location-android
lm2a

1
SettingsApi例とし、トレーニングページ:developer.android.com/training/location/...
androidguy

2
LocationManager!を使用してジオフェンスを作成することもできます。融着位置APIは、Google Playサービスを搭載していないデバイスで動作しますか?
Muhammad Babar 2017年

これは、GPSの有効化/無効化ステータスを確認するための別のより良い方法になる可能性があります fun isLocationEnabled(context: Context): Boolean { val locationMode: Int try { locationMode = Settings.Secure.getInt( context.contentResolver, Settings.Secure.LOCATION_MODE ) } catch (e: SettingNotFoundException) { e.printStackTrace() return false } return locationMode != Settings.Secure.LOCATION_MODE_OFF }
Wahib Ul Haq

32

私の経験では、「より適切な精度」は決して良いという意味ではありません。私が何かを逃していない限り、GPSが使用されていることを確認したい場合は、LocationManagerが唯一の方法です。私たちはアプリで車両を追跡します。また、何かを逃していない限り、Google Play Servicesは非常に不正確な場所をかなり頻繁に提供します。


2
はい、私の経験から、Google Play Servicesが不正確な場所を提供することがあります。
VY

2
はい、Google Play Services Location Services APIは非常に誤解を招く位置情報を提供する可能性があります。WiFiモデムが移動し、WiFiモデムが誤った位置情報で更新されます(つまり、位置がWiFiモデムの位置を更新するAndroidデバイスによってスプーフィングされた場合)。WiFiモデムの三角測量から誤った位置データをもたらす可能性のある他の多くの状況があります。正確な位置情報が必須であるすべてのアプリでは、GPSのみを使用しています。
user1608385

27

LocationManagerの代わりにGoogle Play ServicesのロケーションAPIを使用する必要があります。ドキュメントによると:

アプリに位置認識を追加する方法として、Google Play開発者サービスの位置APIは、Androidフレームワークの位置API(android.location)よりも優先されます。現在AndroidフレームワークのロケーションAPIを使用している場合は、できるだけ早くGoogle Play開発者サービスのロケーションAPIに切り替えることを強くお勧めします。

切り替える理由について、Googleは次のように述べています。

Google Play Servicesの一部であるGoogle Location Services APIは、ロケーションプロバイダー、ユーザーの移動、およびロケーションの精度を自動的に処理する、より強力で高レベルのフレームワークを提供します。また、指定した消費電力パラメーターに基づいて位置更新のスケジューリングを処理します。ほとんどの場合、位置情報サービスAPIを使用することで、バッテリーのパフォーマンスが向上し、適切な精度が得られます。


2
これらの引用元のドキュメントへのリンクはありますか?グーグルが今何か違うことを言っているかどうかを見るのは興味深いでしょう。
エドワードブレイ

3
もちろん、彼らはあなたの位置データを求めているので、彼らはこれを言います!
Flyview

アプリにGoogle Playサービスを追加すると、ユーザーがアプリをインストールすると、アプリを使用するようにGoogle Playサービスを「更新」するように求められます。彼/彼女の電話がほぼ満杯(whatsappミームなどで)またはユーザーがデータを持っていない場合、申し訳ありませんが私の友人
Dr Deo

2
@Flyviewうん!大爆笑、彼らがそれを言う方法は、それが魔法の解決策のように聞こえるようにします!最大の欠点は、デバイスにGoogle Play開発者サービスが必要なことです!!!
varun

25

私はかなり長い間Google Location Services APIを使用しています。位置を決定するためのいくつかのソースを持つことの複雑さをカプセル化するため、これには利点があります。ただし、カプセル化が多すぎるため、奇妙な位置に到達したときに、その奇妙な位置がどこから来たのかを判別する方法がありません。

実際の生活では、実際の位置から数十キロ離れたところにいくつかの異常な値がポップアップ表示されました。唯一の説明は、これらのクレイジーな場所は、GoogleのWi-FiまたはNWKデータベースのエラーから生じているということです。Wi-Fiとネットワークのトポロジは毎日変更されるため、エラーは常に発生します。しかし、残念なことに(そして驚くべきことに)APIは、個々のポジションがどのようにして導出されたかについての情報を提供しません。

ここに画像の説明を入力してください

これにより、速度、加速、方位などの妥当性チェックに基づいて異常値を除外する必要があるという問題が残ります。

...または、古き良きフレームワークAPIに戻ってGPSのみを使用します。これは、Googleが融合APIを改善するまで行うことを決めたものです。


7

Google Play開発者サービスの一部である Google Location Services APIは位置情報プロバイダーユーザーの動き位置情報の精度を自動的に処理する、より強力で高レベルのフレームワークを提供します。また、指定した消費電力パラメーターに基づいて位置更新のスケジューリングを処理します。ほとんどの場合、位置情報サービスAPIを使用すると、バッテリーのパフォーマンスが向上し、より適切な精度が得られます。

2つのAPI間のより詳細なdiffferences GoogleのサービスロケーションAPIをプレイし、Androidのフレームワークの場所のAPIを見つけることができるここに


よろしければ、あなたの答えを使って自分の質問に答えました。どうもありがとう!stackoverflow.com/questions/39852955/...
Leniaal

@レニアルだから、私の答えは賛成に値すると思いませんか?
Dhruvam Gupta 2016

それは3年前の文書です。しかし、ここではプラス1です
ドリュー

5

はい、Google Play Services Location Services APIは非常に誤解を招く位置情報を提供する可能性があります。WiFiモデムが移動し、WiFiモデムが誤った位置情報で更新されます(つまり、位置がWiFiモデムの位置を更新するAndroidデバイスによってスプーフィングされた場合)。WiFiモデムの三角測量から誤った位置データをもたらす可能性のある他の多くの状況があります。正確な位置情報が必須であるすべてのアプリでは、GPSのみを使用しています。


4

GPSサービスに基づく2つのAPI Google Play Service Location APIとAndroid Framework Location APIの違い

FusedLocationProviderClient

  1. 最初のフェッチの場合、場所はnullであってはなりません(つまり、他のアプリはGoogleplayServiceデータベースのLastknownの場所を更新する必要があります。それがnullの場合、回避策が必要です)
  2. 次の順次フェッチでは、requestLocationUpdates()メソッドを使用して場所をフェッチします。
  3. 場所の取得はとにのみ基づいてlocationRequest.setInterval(milliseconds)おりsetFastestInterval(milliseconds)ユーザーの場所の変更には基づいていません
  4. 返されるLatLng値に含まれる10進数の値は7つだけです(例:11.9557996、79.8234599)。正確はありません。
  5. 推奨、アプリの要件が現在の場所の距離を無視できる場合(50〜100メートルの精度)
  6. バッテリーの使用に効果的。

LocationManager API

  1. ユーザーの場所のフェッチは、locationManager.requestLocationUpdates()を使用して呼び出されます
  2. ユーザーの場所の変更時間間隔に基づく場所のフェッチ locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, milliseconds, mindistance, Mylocationlistener)

  3. 返されるLatLng値には、14個の10進値 (例:11.94574594963342 79.81166719458997)の 正確な位置の値が含まれています

  4. メートル単位の精度を必要とする場所ベースのアプリに推奨されます。
  5. バッテリーの使用量は、フェッチ間隔とフェッチ距離に基づいています。

ねえ!1°は最大111_111メートル(20_000_000 / 180)です。したがって、0.0000001°は0.011m = 1 cmです。より良いGPS解像度が必要な場所がわかりません。そして、どうすればGPSの解像度を向上させることができるのかさえわかりません。
バベイ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.