Androidアプリで現在地を定期的に取得する
Androidアプリで位置情報を定期的に取得する事になりましたが、まだまだAndroidアプリ開発に慣れていない身としてはかなり大変でした。 たとえば下記です(心の叫び)。
- 位置情報のドキュメントがたくさんあって、どれが何で何がどれ?!
- サンプルコードのその変数、いつどこで定義したなんなの?!?!
- それはどのファイル(クラス)のどのメソッドに書くんや???
というわけで、いろいろ参考にしつつ試行錯誤しながら作ったサンプルアプリの実装手順を残しておきます。
環境
- Android Studio 3.6
- Pixcel 3a (Android 10)
サンプルアプリを作ってみる
プロジェクトの新規作成
Empty Activity
を選択して作成します。
Google Play Serviceライブラリの追加
app/build.gradle
にcom.google.android.gms:play-services-location:17.0.0
を追加します。
dependencies { ... implementation 'com.google.android.gms:play-services-location:17.0.0' }
Google Play Servicesの最新バージョンは下記で確認できます。
パーミッションの付与
AndroidManifest.xml
に下記3つのパーミッションを追加します。
- ACCESS_COARSE_LOCATION
- ACCESS_FINE_LOCATION
- ACCESS_BACKGROUND_LOCATION
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="jp.test.tryforegroundservicesample"> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <application ... </application> </manifest>
位置情報のパーミッションをリクエストする
ユーザに対して、アプリが位置情報を利用する旨を確認するため、requestPermission()
などを追加します。
class MainActivity : AppCompatActivity() { companion object { private const val PERMISSION_REQUEST_CODE = 1234 } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) requestPermission() } private fun requestPermission() { val permissionAccessCoarseLocationApproved = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED if (permissionAccessCoarseLocationApproved) { val backgroundLocationPermissionApproved = ActivityCompat .checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED if (backgroundLocationPermissionApproved) { // フォアグラウンドとバックグランドのバーミッションがある } else { // フォアグラウンドのみOKなので、バックグラウンドの許可を求める ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION), PERMISSION_REQUEST_CODE ) } } else { // 位置情報の権限が無いため、許可を求める ActivityCompat.requestPermissions(this, arrayOf( Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION ), PERMISSION_REQUEST_CODE ) } } }
緯度経度を表示するTextViewを定義(ID追加)
標準で生成されたactivity_main.xml
にはIDがないため、@+id/locationText
を追加します。
<TextView android:id="@+id/locationText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" />
位置情報サービス クライアントを作成する
位置情報サービス クライアントとして、FusedLocationProviderClient
を追加します。
class MainActivity : AppCompatActivity() { companion object { private const val PERMISSION_REQUEST_CODE = 1234 } private lateinit var fusedLocationClient: FusedLocationProviderClient override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) requestPermission() fusedLocationClient = LocationServices.getFusedLocationProviderClient(this) } private fun requestPermission() { ... } }
位置情報更新のコールバックを実装する
定期的に位置情報を受け取るコールバックを実装します。この処理の中で、画面のTextViewを更新します。
class MainActivity : AppCompatActivity() { companion object { private const val PERMISSION_REQUEST_CODE = 1234 } private lateinit var fusedLocationClient: FusedLocationProviderClient private lateinit var locationCallback: LocationCallback override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) requestPermission() fusedLocationClient = LocationServices.getFusedLocationProviderClient(this) var updatedCount = 0 locationCallback = object : LocationCallback() { override fun onLocationResult(locationResult: LocationResult?) { locationResult ?: return for (location in locationResult.locations){ updatedCount++ locationText.text = "[${updatedCount}] ${location.latitude} , ${location.longitude}" } } } } private fun requestPermission() { ... } }
位置情報取得の開始と終了を実装する
次の3つを実装します。
- startLocationUpdates()
- stopLocationUpdates()
- createLocationRequest()
これらをonResume()
とonPause()
から呼び出します。
class MainActivity : AppCompatActivity() { ... override fun onCreate(savedInstanceState: Bundle?) { ... } override fun onResume() { super.onResume() startLocationUpdates() } override fun onPause() { super.onPause() stopLocationUpdates() } private fun requestPermission() { ... } private fun startLocationUpdates() { val locationRequest = createLocationRequest() ?: return fusedLocationClient.requestLocationUpdates( locationRequest, locationCallback, null) } private fun stopLocationUpdates() { fusedLocationClient.removeLocationUpdates(locationCallback) } private fun createLocationRequest(): LocationRequest? { return LocationRequest.create()?.apply { interval = 10000 fastestInterval = 5000 priority = LocationRequest.PRIORITY_HIGH_ACCURACY } } }
動作確認
アプリをビルドして起動します。起動すると位置情報を取得するか聞かれるため、「常に許可」を選択します。
位置情報(緯度・経度)がバッチリ表示されました!! 最初の数字[3]
は、更新した回数です。
さいごに
公式ドキュメントを参考にしながら、位置情報を定期取得するサンプルアプリを作ってみました。 どなたかの参考になれば幸いです。