0Pricing
Android Academy · レッスン

ユーザーの位置情報を取得する

Fused Location Providerの基本を学びます。

「ユーザーの位置情報を取得する」はCoddyKit上の無料Android Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAndroid Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Android Academyコースには全4レッスンが含まれています。

ユーザーはどこにいるか

位置情報を利用するアプリの多くは、まず現在、デバイスはどこにあるのかという疑問から始まります。Androidでは、Google Play servicesの一部であるFused Location Providerを通じてこれに答えます。

このレッスンでは、依存関係を追加し、単一の位置情報を取得し、継続的な更新を監視して、その結果をComposeに表示します。

Fused Providerを使う理由

Androidには、GPS、Wi-Fi、携帯電話基地局など、複数の位置情報ソースがあります。Fused Location Providerはそれらをインテリジェントに組み合わせ、バッテリー消費を抑えながら最適な位置情報を提供します。

現在では、低レベルのLocationManagerを直接使うことはほとんどありません。fused clientのほうが、より簡単で賢く処理できます。

// build.gradle.kts (module)
dependencies {
    implementation("com.google.android.gms:play-services-location:21.3.0")
}

パーミッションを宣言する

位置情報は機密性の高いリソースです。AndroidManifest.xmlでパーミッションを宣言してください。正確な位置情報にはACCESS_FINE_LOCATION、おおよその位置情報にはACCESS_COARSE_LOCATIONを使用します。

宣言は最初の手順にすぎません。実行時にもリクエストする必要があります(詳しくは後のレッスンで扱います)。

<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Fused Clientを作成する

LocationServicesからFusedLocationProviderClientを取得します。ComposeではLocalContext.currentでコンテキストを取得し、再コンポジションのたびにクライアントが再作成されないようrememberします。

import com.google.android.gms.location.LocationServices

@Composable
fun rememberFusedClient() = run {
    val context = LocalContext.current
    remember {
        LocationServices.getFusedLocationProviderClient(context)
    }
}

最後に認識された位置情報を取得する

最も速く取得できるのはlastLocationです。これは、システムがすでにキャッシュしている最新の位置情報です。戻り値はTaskなので、成功リスナーを登録します。

最近どのアプリからも位置情報がリクエストされていない場合はnullになる可能性があるため、必ずnullチェックしてください。

@SuppressLint("MissingPermission")
fun fetchLastLocation(
    client: FusedLocationProviderClient,
    onResult: (Location?) -> Unit
) {
    client.lastLocation
        .addOnSuccessListener { location -> onResult(location) }
        .addOnFailureListener { onResult(null) }
}

コルーチンでTaskを待機する

コールバックはすぐにネストしてしまいます。kotlinx-coroutines-play-servicesライブラリは.await()を追加するため、位置情報を見通しのよいsuspendコードで取得できます。

import kotlinx.coroutines.tasks.await

@SuppressLint("MissingPermission")
suspend fun currentLastLocation(
    client: FusedLocationProviderClient
): Location? {
    return client.lastLocation.await()
}

最新の位置情報をリクエストする

lastLocationは古い可能性があります。最新の位置情報を取得するには、優先度を指定してgetCurrentLocationを呼び出します。PRIORITY_HIGH_ACCURACYはGPSを使用し、PRIORITY_BALANCED_POWER_ACCURACYはバッテリーを節約します。

import com.google.android.gms.location.Priority
import com.google.android.gms.location.CurrentLocationRequest

@SuppressLint("MissingPermission")
suspend fun freshLocation(
    client: FusedLocationProviderClient
): Location? {
    val request = CurrentLocationRequest.Builder()
        .setPriority(Priority.PRIORITY_HIGH_ACCURACY)
        .build()
    return client.getCurrentLocation(request, null).await()
}

位置情報を継続的に更新する

ナビゲーションやトラッキングでは、更新情報のストリームが必要です。間隔を指定してLocationRequestを作成し、requestLocationUpdatesでLocationCallbackを登録します。

処理が終わったら、バッテリーを節約するため必ず更新を停止してください。

import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationResult
import com.google.android.gms.location.LocationCallback

val request = LocationRequest.Builder(
    Priority.PRIORITY_HIGH_ACCURACY,
    5000L // 5 seconds
).build()

val callback = object : LocationCallback() {
    override fun onLocationResult(result: LocationResult) {
        result.lastLocation?.let { /* use it */ }
    }
}

更新情報をFlowとして扱う

一般的なパターンでは、更新情報をcallbackFlowでラップします。これにより、利用側は位置情報をcollectでき、awaitCloseを通じてcollectが終了すると更新も自動的に停止します。

import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow

@SuppressLint("MissingPermission")
fun FusedLocationProviderClient.locationFlow(request: LocationRequest) = callbackFlow {
    val cb = object : LocationCallback() {
        override fun onLocationResult(result: LocationResult) {
            result.lastLocation?.let { trySend(it) }
        }
    }
    requestLocationUpdates(request, cb, Looper.getMainLooper())
    awaitClose { removeLocationUpdates(cb) }
}

Composeに位置情報を表示する

単発の読み取りにはLaunchedEffectを、ストリームにはcollectAsStateWithLifecycleを使って、コンポーザブル内で結果をcollectします。その後、座標を表示します。

@Composable
fun LocationLabel(client: FusedLocationProviderClient) {
    var location by remember { mutableStateOf<Location?>(null) }
    LaunchedEffect(Unit) {
        location = freshLocation(client)
    }
    Text(
        location?.let { "Lat ${it.latitude}, Lng ${it.longitude}" }
            ?: "Locating..."
    )
}

バッテリーと精度のトレードオフ

位置情報は、モバイルアプリで特にバッテリー消費の大きい機能の1つです。要件を満たせる範囲で最も低い精度を選び、許容できる中で最も長い更新間隔を使用し、画面が閉じたら必ず更新を停止してください。

高精度かつ高頻度の更新は、バッテリーを急速に消費します。アクティブなナビゲーションに限って使用してください。

理解度チェック

suspend関数を使って、今この瞬間の最も正確な位置情報を1件取得する必要があります。どの方法が最適ですか?

まとめ

これで、デバイスの位置情報を読み取れるようになりました。

  • play-services-locationを追加し、ACCESS_FINE/COARSE_LOCATIONを宣言します。
  • LocationServicesからFusedLocationProviderClientを取得します。
  • キャッシュ済みの位置情報にはlastLocationを、最新の位置情報にはgetCurrentLocationを使用します。
  • requestLocationUpdatesまたはcallbackFlowで更新情報をストリーム処理し、バッテリー節約のため停止します。

次は、マーカーを描画し、取得した座標へカメラを移動します。

よくある質問

「ユーザーの位置情報を取得する」レッスンは無料ですか?

はい。「ユーザーの位置情報を取得する」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Android Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Android Academyコースには全4レッスンが含まれています。

「ユーザーの位置情報を取得する」で何を学びますか?

Fused Location Providerの基本を学びます。 ブラウザで直接実行するハンズオンコードでAndroid Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Android Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのAndroid Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「ユーザーの位置情報を取得する」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このAndroid Academyレッスンでコードを書いて実行できますか?

はい。すべてのAndroid Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 地図を表示する
  2. ユーザーの位置情報を取得する
  3. マーカーとカメラ
  4. 正しい位置情報権限の扱い
← Android Academyに戻る