【Kotlin/Android】現在地の位置情報を取得する方法!FusedLocation

【Kotlin/Android】現在地の位置情報を取得する方法!FusedLocation

この記事からわかること

  • Kotlin/Android Studio現在地位置情報取得する方法
  • FusedLocation使い方
  • 定期的に位置情報を取得するには?

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

現在値の位置情報を取得する方法

Androidアプリで現在値の位置情報を取得するにはGoogleが提供しているLocation SDK(FusedLocation)を使用します。取得できる位置情報は緯度と経度情報を含んだLocationオブジェクトになります。

まずは「ボタンをクリックしたタイミングで現在の位置情報を取得する処理」を実装してみます。

実装の流れ

  1. FusedLocationの導入
  2. パーミションの追加
  3. 許可申請
  4. 現在値を取得

1.FusedLocationの導入

まずはプロジェクト内でSDKを使用できるように「build.gradle(Module)」に以下を追加します。

公式リファレンス:Location SDK


dependencies {
    implementation 'com.google.android.gms:play-services-location:21.3.0'
}

2.パーミションの追加

続いて位置情報を取得できるようにパーミションを追加します。バックグラウンドでも取得したいならACCESS_BACKGROUND_LOCATIONを追加します。


<!-- 正確な位置(GPS) -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!-- おおよその位置(Wi-Fiやネットワーク) -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<!-- backgroundでの位置情報   -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

公式リファレンス:android.permission.ACCESS_FINE_LOCATION
公式リファレンス:android.permission.ACCESS_COARSE_LOCATION
公式リファレンス:android.permission.ACCESS_BACKGROUND_LOCATION

3.許可申請

続いて位置情報の許可をユーザーにリクエストします。


class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

        // 許可申請ダイアログを表示
        launcher.launch(
            arrayOf(
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION,
            )
        )
    }

    private val launcher =
        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
            it
            val fineLocation = it[Manifest.permission.ACCESS_FINE_LOCATION] ?: false
            val coarseLocation = it[Manifest.permission.ACCESS_COARSE_LOCATION] ?: false

            if (fineLocation && coarseLocation) {
                Toast.makeText(this, "許可されました", Toast.LENGTH_SHORT)
                    .show()
            } else {
                Toast.makeText(this, "否認されました", Toast.LENGTH_SHORT)
                    .show()
            }
        }
}

4.現在値を取得

実際に現在値を取得するにはlastLocationからaddOnSuccessListenerを呼び出し、ラムダ式の引数でLocationオブジェクトとして取得することができます。ただしここで取得できるのはあくまで最後に取得していた位置情報であって位置情報を取得することを要求しているわけではないので注意してください。

class MainActivity : AppCompatActivity() {

    private lateinit var fusedLocationClient: FusedLocationProviderClient

    override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

      // ①位置情報取得のためのクライアントをインスタンス化
      fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)

      binding.doneButton.setOnClickListener{
          // ②パーミションチェック
          if (ActivityCompat.checkSelfPermission(
                  this,
                  Manifest.permission.ACCESS_FINE_LOCATION
              ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
                  this,
                  Manifest.permission.ACCESS_COARSE_LOCATION
              ) != PackageManager.PERMISSION_GRANTED
          ) {
              Log.e("位置情報", "権限が許可されていないよ")
              return@setOnClickListener
          }

          // ③現在値の位置情報(最後に取得した位置情報)を取得
          fusedLocationClient.lastLocation
              .addOnSuccessListener { location : Location? ->
                  location?.let {
                      Log.e("位置情報", location.toString())
                      Log.e("位置情報:緯度", location.latitude.toString())
                      Log.e("位置情報:軽度", location.longitude.toString())
                  }?: run {
                      Log.e("位置情報", "位置情報取得失敗")
                  }
              }
      }
    }
}

定期的に位置情報を取得する

位置情報は常に変化していくものなので、定期的に位置情報を取得するように実装してみたいと思います。これを叶えるためには以下のクラスが必要になってきます。

LocationRequest

LocationRequestは位置情報取得において、位置情報の取得頻度や精度、タイムアウトなどの設定するオブジェクト。

LocationCallback

LocationCallbackは位置情報の更新を受け取るためのコールバッククラス。

実装の流れ

  1. LocationRequestの作成
  2. LocationCallbackの実装
  3. requestLocationUpdatesメソッドの実行

1.LocationRequestの作成

LocationRequestを作成して位置情報を取得する間隔などの設定を行います。Builderメソッドの第一引数にはPriority位置情報の精度を、第二引数にはLong更新間隔をミリ秒数で渡します。


// importは以下なので注意
import com.google.android.gms.location.LocationRequest
// import android.location.LocationRequest // これは ×
  
class MainActivity : AppCompatActivity() {
    private lateinit var locationRequest: LocationRequest

    override fun onCreate(savedInstanceState: Bundle?) {
      // 〜〜〜〜〜〜〜〜〜〜

      // LocationRequestの設定
      // Builderの引数には精度と更新間隔(例:5秒)を渡す
      locationRequest = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 5000)
          .build()
    }
}

設定できる精度は以下のようになっています。

2.LocationCallbackの実装

続いて位置情報を取得した際に実行したい処理LocationCallback型で定義します。


class MainActivity : AppCompatActivity() {
    private lateinit var locationCallback: LocationCallback

    override fun onCreate(savedInstanceState: Bundle?) {
        // 〜〜〜〜〜〜〜〜〜〜

        // LocationCallbackの定義
        locationCallback = object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult) {
                for (location in locationResult.locations) {
                    Log.e("位置情報", location.toString())
                    Log.e("位置情報:緯度", location.latitude.toString())
                    Log.e("位置情報:軽度", location.longitude.toString())
                }
            }
        }
    }
}

3.requestLocationUpdatesメソッドの実行

最後にrequestLocationUpdatesメソッドを使用して 位置情報の更新と観測を開始します。引数にLocationRequestLocationCallbackを渡し、コールバックを実行したいスレッドを3つ目に渡します。


class MainActivity : AppCompatActivity() {
    private lateinit var locationCallback: LocationCallback

    override fun onCreate(savedInstanceState: Bundle?) {
        // 〜〜〜〜〜〜〜〜〜〜

        // 位置情報更新&観測開始
        fusedLocationClient.requestLocationUpdates(
            locationRequest,
            locationCallback,
            Looper.getMainLooper() // メインスレッドで実行
        )
    }

    // 観測のキャンセルも忘れずに
    override fun onPause() {
        super.onPause()
        // アクティビティが一時停止したときに位置情報の更新を停止
        fusedLocationClient.removeLocationUpdates(locationCallback)
    }
}

これで定期的に位置情報を取得する処理が実装できました。実際に5秒ごとに位置情報が取得できているか試してみてください。

バックグラウンドスレッドで実行したい場合

おまけでバックグラウンドスレッドで実行したい場合は以下のように実装すればOKです。

val handlerThread = HandlerThread("LocationHandlerThread")
handlerThread.start()
val looper = handlerThread.looper
fusedLocationClient.requestLocationUpdates(
  locationRequest, 
  locationCallback, 
  looper
)

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index