位置情報の取得
参考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)
}