ユーザーの位置情報を取得する
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フィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 地図を表示する
- ユーザーの位置情報を取得する
- マーカーとカメラ
- 正しい位置情報権限の扱い