位置情報の取得
参考1: Kotlinを使用したAndroid端末の位置情報取得
参考2: 位置情報を取得する仕組み
現在の位置情報のプロバイダは、GPS・IPアドレス・無線APのMACアドレスの3つ。
FusedLocationProviderClientを用いることで、利用するプロバイダを自動で選択しながら位置情報を取得することができる。
FusedLocationProviderClient
Googleが公開するGoogle Play Service(=API)が提供するLocationライブラリに含まれる、
位置情報の取得を行うメソッドを定義するクラス。
FusedLocationProviderClientクラスを利用する手順は、以下の通り。
Google Play Service(=API)の追加appモジュールへのLocationライブラリ(=FusedLocationProviderClientクラスの依存関係ライブラリ)の追加
APIの追加
APIの追加は、Android StudioのPreferenceから行うことができる。
Locationライブラリの追加
Locationライブラリの追加は、Android StudioのFile→Project Structureから行うことができる。
FusedLocationProviderClientを利用した現在地の取得
参考: 直近の位置情報を取得する
FusedLocationProviderClientを利用して現在の位置情報を取得する手順は、以下の通り。
FusedLocationProviderClient・LocationRequest・コールバック処理プロパティをlateinitで用意し、アクティビティの初期化時(=onCreate())に生成・代入位置情報の取得タイミング(=LocationRequestオブジェクト)を設定LocationCallbackクラスの実装クラスを用意し、位置情報の取得後に呼び出されるコールバック処理を記述マニフェストファイル(=AndroidManifest.xml)にアプリケーションが端末の位置情報を利用するための権限(=パーミッション)を付与アクティビティの表示直前(=onResume())に、ユーザからパーミッションが付与されていない場合はユーザに対してパーミッションダイアログを表示する処理を記述パーミッションダイアログに対してユーザが操作を行った場合に呼び出される処理を記述ユーザからパーミッションが付与されている場合のみ位置情報を取得する処理を記述アクティビティ非表示の直前(=onPause())に、位置情報の取得処理を停止する処理を記述
LocationRequest
FusedLocationProviderClientによる位置情報の取得(=リクエスト)タイミングを管理するクラス。
取得タイミングを変更することによって、参照する位置情報の精度を調整できる。
LocationCallback
位置情報の取得処理が終了した場合に呼び出されるonLocationResult()メソッド(=抽象メソッド)を定義する抽象クラス。
パーミッションダイアログ
ユーザに対して、パーミッションチェックを求めるダイアログ。
各種プロパティの宣言・代入
位置情報の取得を行うFusedLocationProviderClient、
その取得タイミングを管理するLocationRequestオブジェクトはリソースを大量に消費するため、
アクティビティを起動するタイミング(=onCreate())でオブジェクトを生成し代入できるよう、lateinitキーワードを用いて宣言する。
また、後でLocationCallbackクラスの実装クラスを独自に定義するため、事前に実装クラスのプロパティも同じくlateinitキーワードを用いて宣言する。
なお、FusedLocationProviderClientオブジェクトを生成する際は、LocationServicesクラスのgetFusedLocationProviderClient()メソッドを利用する。
lateinit
参考: lateinit変数
宣言時に初期値を設定(=初期化)せず、後から初期化を行う参照型オブジェクトに付与するキーワード。
lateinitキーワードを用いて宣言する場合の初期値はnullであるため、必ず読み書き可能(=ミュータブル)な変数varを用いて定義する。
LocationServices
位置情報を取得するFusedLocationProviderClient、
ジオフェンシングを行うGeofencingClient、
Android端末の設定画面を起動するSettingsClientのオブジェクトを生成するメソッドを定義するクラス。
ジオフェンシング
位置情報を利用して特定の場所への出入りを管理する技術。
定義
// FusedLocationProviderClientオブジェクトの生成
LocationServices.getFusedLocationProviderClient(
context: Context
): FisedLocationProviderClient
// パラメータ
// context: FusedLocationProviderClientを利用するコンテキスト
// LocationRequestオブジェクトの生成
LocationRequest.create(): LocationRequest
サンプルコード
class MainActivity : AppCompatActivity() {
...
// FusedLocationProviderClientプロパティ
// -> オブジェクトがリソースを大量に消費する場合、
// アクティビティ初期化時にオブジェクトを生成(=初期化)できるよう
// lateinitキーワードを用いて宣言
private lateinit var _fusedLocationClient: FusedLocationProviderClient
// LocationRequestプロパティ
private lateinit var _locationRequest: LocationRequest
// OnUpdateLocationプロパティ
// <- 抽象クラスであるLocationCallbackの実装クラス
private lateinit var _onUpdateLocation: OnUpdateLocation
// アクティビティ初期化時に呼び出される処理
override fun onCreate(savedInstanceState: Bundle?) {
...
// FusedLocationProviderClientプロパティの初期化
_fusedLocationClient = LocationServices.getFusedLocationProviderClient(this@MainActivity)
// LocationRequestプロパティの初期化
_locationRequest = LocationRequest.create()
// OnUpdateLocationプロパティの初期化
_onUpdateLocation = OnUpdateLocation()
}
}
位置情報の取得タイミングの設定
位置情報の取得タイミングを管理するLocationRequestのプロパティに、各種設定値を代入する。
なお、位置情報の取得精度を表すpriorityプロパティに代入する値は、LocationRequestのクラス定数を利用する。
LocationRequestクラスのプロパティ
| プロパティ名 | 内容 | 既定値 |
|---|---|---|
interval |
基本となる取得間隔 |
3600000[ms] |
fastestInterval |
最短の取得間隔 |
600000[ms] |
priority |
位置情報の取得精度 ※ LocationRequestクラス定数を利用 |
PRIORITY_HIGH_ACCURACY |
位置情報の取得精度を表すLocationRequestクラス定数
LocationRequestクラスのpriorityプロパティは、位置情報の取得精度に関する設定値を指す。
なお、PRIORITY_NO_POWERに関しては、電力消費を最小限に抑えるため、
別のアプリケーションによって取得されたタイミングでその位置情報を利用する。
| 定数名 | 内容 | 値 |
|---|---|---|
PRIORITY_HIGH_ACCURACY |
高精度番地レベル |
100(既定) |
PRIORITY_BALANCED_POWER_ACCURACY |
中精度丁目レベル |
102 |
PRIORITY_LOW_POWER |
低精度市・区レベル |
104 |
PRIORITY_NO_POWER |
他アプリに依存 | 105 |
サンプルコード
class MainActivity : AppCompatActivity() {
...
// LocationRequestプロパティ
private lateinit var _locationRequest: LocationRequest
// アクティビティ初期化時に呼び出される処理
override fun onCreate(savedInstanceState: Bundle?) {
...
// LocationRequestプロパティの初期化
_locationRequest = LocationRequest.create()
// LocationRequestプロパティがnullでないことを保証
// <- lateinitで宣言したオブジェクトのプロパティを変更する場合は
// オブジェクトがnullでないことの保証が推奨
_locationRequest?.let {
// 基本取得間隔[ms]
it.interval = 5000
// 最短取得間隔[ms]
it.fastestInterval = 1000
// 位置情報の取得精度
it.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
...
}
}
LocationCallbackクラスの実装
位置情報の取得処理が終了した場合のコールバックメソッドにあたるonLocationResult()メソッドは、
LocationCallbackクラスで定義される、位置情報が利用可能になった際に呼び出される抽象メソッドであるため、
LocationCallbackクラスの実装クラスを用意し、オーバーライドして位置情報の取得処理が終了した場合に実行する処理を記述する。
また、LocationCallback.onLocationResult()メソッドは引数にLocationResultオブジェクトをとるが、
位置情報が取得できなかった場合はその値がnullとなるため、
コールバック処理を記述する際に、セーフコール演算子(=?)とlet関数を用いてNonNullであることを保証する必要がある。
さらに、LocationResultオブジェクトの、取得した直近の位置情報を格納するlastLocationプロパティ(=Locationオブジェクト)は、
端末の再起動直後など、場合によっては値がnullであることがあるため、同様に継続処理を行う場合はNonNullであることを保証する必要がある。
LocationResult
位置情報の取得処理結果を、過去の取得結果も含めてリストで管理するクラス。
Location
経緯度・タイムスタンプ・方位・高度・速度などの地理的情報を保持するクラス。
定義
// デバイスの位置情報が利用可能である場合に呼び出される抽象メソッド
LocationCallback.onLocationResult(result: LocationResult?): Unit
// パラメータ
// result: 利用可能な最新の位置情報の取得結果を保持するLocationResultオブジェクト
サンプルコード
// 位置情報の取得処理終了時に呼び出される処理の実装クラス
private inner class OnUpdateLocation: LocationCallback() {
// 位置情報の取得処理終了時に呼び出される処理
override fun onLocationResult(result: LocationResult?) {
// 取得結果がnullでないことを保証
result?.let {
// 直近の位置情報を保持するlastLocationプロパティ
val location = it.lastLocation
// 直近の位置情報がnullでないことを保証
location?.let {
// 直近の経緯度
_latitude = it.latitude
_longitude = it.longitude
...
}
}
}
}
マニフェストファイルへのパーミッションの記述
アプリケーションが端末の位置情報を利用できるよう、マニフェストファイル(=AndroidManifest.xml)に<uses-permission>タグを追記する。
なお、マニフェストファイルに記述したタグは、あくまで「ユーザによる利用権限(=パーミッション)の付与が必要な項目」であるため、
別途ユーザに対してパーミッションダイアログを表示することで、ユーザから利用許可を得られるようにする必要がある。
サンプルコード
<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
...
</manifest>
パーミッションダイアログの表示
アプリケーションが端末情報を利用する場合、ユーザから利用権限(=パーミッション)を付与してもらうために、
アクティビティの表示直前(=onResume())にパーミッションダイアログを表示する必要がある。
ただし、事前(以前)にユーザから既にパーミッションが付与されている場合はパーミッションダイアログを表示する必要はないため、
パーミッションダイアログを表示する前にセルフパーミッションチェックを行う必要がある。
なお、ユーザからアプリケーションに対して設定されたパーミッション情報を取得するメソッドはContextCompatクラスで定義され、
パーミッションダイアログを表示するメソッドはActivityCompatクラスで定義される。
ここで、ContextCompatクラスはアクティビティクラスが間接的に継承するActivityCompatクラスが継承しているため、
ActivityCompatクラスのメソッドとして利用することができる。
また、アプリケーションに対して設定されたパーミッションの値はPackageManagerのクラス定数を利用する。
PackageManager
各アプリケーションに固有に設定された情報を取得するメソッドや、パーミッション情報をクラス定数として用意する抽象クラス。
定義
// アクティビティによるセルフパーミッションチェック
// <- ActivityCompatはContextCompatクラスを継承しているため、
// ActivityCompat.checkSelfPermission()としても呼び出せる
ContextCompat.checkSelfPermission(
@NonNull context: Context,
@NonNull permission: String
): Int
// パラメータ
// context: パーミッションチェックを行うアクティビティクラス(=コンテキスト)
// permission: パーミッションチェックを行うパーミッション名
// -> "Manifest.permission.<パーミッションの種類>"で記述
// パーミッションダイアログの表示
ActicityCompat.requestPermissions(
@NonNull activity: Activity,
@NonNull permissions: Array<String!>,
@IntRange(0) requestCode: Int
): Unit
// パラメータ
// activity: パーミッションダイアログを表示するアクティビティ
// permissions: ユーザに許可を求めるパーミッションリスト
// requestCode: 下記
// ActivityCompat.OnRequestPermissionsResultCallbackインタフェースの
// onRequestPermissionsResult()メソッド(後述)と一対一で対応させる、
// 0以上のInt型で表す固有のリクエストコード
パーミッション情報を表すPackageManagerクラス定数
| 定数名 | 内容 |
|---|---|
PERMISSION_GRANTED |
許可 |
PERMISSION_DENIED |
不許可 |
サンプルコード
class MainActivity : AppCompatActivity() {
// アクティビティの表示直前に呼び出される処理
override fun onResume() {
super.onResume()
// アクティビティによるセルフパーミッションチェックの結果、
// 位置情報の利用が許可されていない場合の処理
if (ActivityCompat.checkSelfPermission(
this@MainActivity,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
// パーミッションチェックを行うパーミッションリスト
val permissions = arrayOf(Manifest.permission.ACCESS_FINE_LOCATION)
// ユーザに許可を求めるパーミッションダイアログの表示
ActivityCompat.requestPermissions(
this@MainActivity,
permissions,
1000
)
// onResume()メソッドの終了
return
}
... // アクティビティによるセルフパーミッションチェックの結果、
// 位置情報の利用が許可されている場合の処理
}
}
パーミッションダイアログが操作された場合の処理
パーミッションダイアログが操作された場合に自動的に呼び出される処理(=コールバック処理)は、ActivityCompatクラス内で定義されるOnRequestPermissionsResultCallbackインタフェースのonRequestPermissionsResult()メソッドをオーバーライドして定義する。
onRequestPermissionsResult()メソッドはパーミッションダイアログを表示する処理とリクエストコードで紐づくため、パーミッション情報をそのまま受け取ることができるが、
Android Studioの仕様上、アクティビティによるセルフパーミッションチェックも必要とする。
定義
// パーミッションダイアログが操作された場合に呼び出されるコールバックメソッド
ActivityCompat.OnRequestPermissionsResultCallback.onRequestPermissionsResult(
requestCode: Int,
@NonNull permissions: Array<String!>,
@NonNull grantResults: IntArray
): Unit
// パラメータ
// requestCode: ActivityCompat.requestPermissions()メソッドと一対一で対応させる、
// (0以上の)Int型で表す固有のリクエストコード
// permissions: ユーザに許可を求めたパーミッションリスト
// grantResults: PackageManagerのクラス定数で表される、
// ユーザが設定したパーミッションの値を格納するリスト
// <- パーミッションリスト内の順番(=インデックス番号)とそれぞれ一対一で対応
サンプルコード
// パーミッションダイアログが操作された場合に呼び出されるコールバックメソッド
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
// ユーザ操作によって利用許可が下りていた場合
if (requestCode == 1000 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// アプリケーション側でセルフパーミッションチェックを行った結果、拒否されていた場合
if (ActivityCompat.checkSelfPermission(
this@MainActivity,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
// 何も実行せずonRequestPermissionsResult()メソッドを終了
return
}
... // アクティビティによるセルフパーミッションチェックの結果、
// 位置情報の利用が許可されている場合の処理
}
}
位置情報の取得
参考: 研修8日目(Looper)
FusedLocationProviderClientクラスのrequestLocationUpdates()メソッドを用いて位置情報を取得する。
ただし、位置情報の取得処理を行う場合は、事前にアクティビティによるセルフパーミッションチェックを行う必要がある。
セルフパーミッションチェックの結果、ユーザからパーミッションを付与されていない場合は、
「何も実行しない」または「パーミッションダイアログの表示」などの処理を行う必要がある。
なお、requestLocationUpdates()メソッドは、
位置情報の取得間隔を表すLocationRequestオブジェクト、
位置情報に変更(=更新)があった場合に呼び出される処理を実装したLocationCallbackの実装クラスオブジェクト、
その処理を動作させるスレッドを指定するためのLooperオブジェクトを引数にとる。
定義
FusedLocationProviderClient.requestLocationUpdates(
request: LocationRequest,
callback: LocationCallback,
looper: Looper
): Unit
// パラメータ
// request: 位置情報更新に関する設定情報を保持するLocationRequestオブジェクト
// callback: 位置情報に変更(=更新)があった場合に呼び出される
// LocationCallbackの実装クラスオブジェクト
// looper: 処理の動作スレッドを指定するLooperオブジェクト
サンプルコード
// FusedLocationProviderClientプロパティの初期化
_fusedLocationClient = LocationServices.getFusedLocationProviderClient(this@MainActivity)
// LocationRequestプロパティの初期化
_locationRequest = LocationRequest.create()
// LocationCallbackプロパティの初期化
_onUpdateLocation = OnUpdateLocation()
// アクティビティによるセルフパーミッションチェックの結果、
// 位置情報の利用が許可されていない場合の処理
// -> パーミッションダイアログを表示
if (ActivityCompat.checkSelfPermission(
this@MainActivity,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
// パーミッションチェックを行うパーミッションリスト
val permissions = arrayOf(Manifest.permission.ACCESS_FINE_LOCATION)
// パーミッションダイアログの表示
ActivityCompat.requestPermissions(
this@MainActivity,
permissions,
1000
)
// 何も実行せずスコープを抜ける
return
}
// アクティビティによるセルフパーミッションチェックの結果、
// 位置情報の利用が許可されている場合の処理
// -> 位置情報を取得
_fusedLocationClient.requestLocationUpdates(
_locationRequest,
_onUpdateLocation,
mainLooper
)
位置情報の取得処理の停止
アクティビティの終了時(=onPause())など、位置情報を取得する必要がなくなる場合は、
FusedLocationProviderClientクラスのremoveLocationUpdates()メソッドを用いて
位置情報の取得処理を停止させる必要がある。
定義
FusedLocationProviderClient.removeLocationUpdates(
callback: LocationCallback
): Unit
// パラメータ
// callback: 位置情報に変更(=更新)があった場合に呼び出される
// LocationCallbackの実装クラスオブジェクト
サンプルコード
// FusedLocationProviderClientプロパティの初期化
_fusedLocationClient = LocationServices.getFusedLocationProviderClient(this@MainActivity)
// LocationCallbackプロパティの初期化
_onUpdateLocation = OnUpdateLocation()
// アクティビティの非表示直前に呼び出される処理
override fun onPause() {
super.onPause()
// 位置情報の取得を停止
_fusedLocationClient.removeLocationUpdates(_onUpdateLocation)
}



