Androidでのユーザーの場所
Androidでのユーザーの現在地の取得は、iOSの場合よりも簡単ではありません。混乱を始めるには、2つのまったく異なる方法があります。1つ目はのAndroid APIを使用してandroid.location.LocationListener
おり、2つ目はGoogle Play Services APIを使用していますcom.google.android.gms.location.LocationListener
。両方を見てみましょう。
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を使用すると、バッテリーのパフォーマンスが向上し、より適切な精度が得られるとも述べています。今混乱が始まります!
- 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を確認することをお勧めします。