Panduan ini kompatibel dengan Health Connect versi 1.1.0-alpha12 atau yang lebih baru.
Rute olahraga memungkinkan pengguna melacak rute GPS untuk aktivitas olahraga terkait dan membagikan peta olahraga mereka ke aplikasi lain.
Memeriksa ketersediaan Health Connect
Sebelum mencoba menggunakan Health Connect, aplikasi Anda harus memverifikasi bahwa Health Connect tersedia
di perangkat pengguna. Health Connect mungkin tidak diinstal di semua perangkat atau mungkin dinonaktifkan.
Anda dapat memeriksa ketersediaan menggunakan metode HealthConnectClient.getSdkStatus().
Cara memeriksa ketersediaan Health Connect
fun checkHealthConnectAvailability(context: Context) { val providerPackageName = "com.google.android.apps.healthdata" val availabilityStatus = HealthConnectClient.getSdkStatus(context, providerPackageName) if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE) { // Health Connect is not available. Guide the user to install/enable it. // For example, show a dialog. return // early return as there is no viable integration } if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED) { // Health Connect is available but requires an update. // Optionally redirect to package installer to find a provider, for example: val uriString = "market://details?id=$providerPackageName&url=healthconnect%3A%2F%2Fonboarding" context.startActivity( Intent(Intent.ACTION_VIEW).apply { setPackage("com.android.vending") data = Uri.parse(uriString) putExtra("overlay", true) putExtra("callerId", context.packageName) } ) return } // Health Connect is available, obtain a HealthConnectClient instance val healthConnectClient = HealthConnectClient.getOrCreate(context) // Issue operations with healthConnectClient }
Bergantung pada status yang ditampilkan oleh getSdkStatus(), Anda dapat memandu pengguna
untuk menginstal atau mengupdate Health Connect dari Google Play Store jika perlu.
Panduan ini memberikan informasi tentang cara meminta izin dari pengguna dan juga menjelaskan cara aplikasi menerima izin untuk menulis data rute sebagai bagian dari sesi olahraga.
Fungsi baca dan tulis untuk rute olahraga mencakup:
- Aplikasi membuat izin tulis baru untuk rute olahraga.
- Penyisipan dilakukan dengan menulis sesi olahraga beserta rute sebagai kolomnya.
- Membaca:
- Untuk pemilik sesi, data diakses menggunakan pembacaan sesi.
- Dari aplikasi pihak ketiga, melalui dialog yang memungkinkan pengguna memberikan pembacaan rute satu kali.
Jika pengguna tidak memiliki izin tulis dan rute tidak ditetapkan, rute tidak akan diperbarui.
Jika aplikasi Anda memiliki izin tulis rute dan mencoba memperbarui sesi dengan meneruskan objek sesi tanpa rute, rute yang sudah ada akan dihapus.
Ketersediaan fitur
Untuk menentukan apakah perangkat pengguna mendukung latihan terencana di Health Connect, periksa ketersediaanFEATURE_PLANNED_EXERCISE di klien:
if (healthConnectClient
.features
.getFeatureStatus(
HealthConnectFeatures.FEATURE_PLANNED_EXERCISE
) == HealthConnectFeatures.FEATURE_STATUS_AVAILABLE) {
// Feature is available
} else {
// Feature isn't available
}
Izin yang diperlukan
Akses ke rute olahraga dilindungi oleh izin berikut:
android.permission.health.READ_EXERCISE_ROUTESandroid.permission.health.WRITE_EXERCISE_ROUTE
READ_EXERCISE_ROUTES berbentuk jamak, sedangkan
WRITE_EXERCISE_ROUTE berbentuk tunggal.
Untuk menambahkan kemampuan rute olahraga ke aplikasi Anda, mulailah dengan meminta
izin untuk jenis data ExerciseSession.
Berikut adalah izin yang harus Anda deklarasikan agar dapat menulis rute olahraga:
<application>
<uses-permission
android:name="android.permission.health.WRITE_EXERCISE_ROUTE" />
...
</application>
Untuk membaca rute olahraga, Anda harus meminta izin berikut:
<application>
<uses-permission
android:name="android.permission.health.READ_EXERCISE_ROUTES" />
...
</application>
Anda juga harus mendeklarasikan izin olahraga, karena setiap rute dikaitkan dengan sesi olahraga (satu sesi = satu olahraga).
Untuk meminta izin, gunakan
metode PermissionController.createRequestPermissionResultContract() saat
Anda pertama kali menghubungkan aplikasi ke Health Connect. Beberapa izin yang mungkin
ingin Anda minta adalah:
- Membaca data kesehatan dan kebugaran, termasuk data rute:
HealthPermission.getReadPermission(ExerciseSessionRecord::class) - Menulis data kesehatan dan kebugaran, termasuk data rute:
HealthPermission.getWritePermission(ExerciseSessionRecord::class) - Menulis data rute olahraga:
HealthPermission.PERMISSION_WRITE_EXERCISE_ROUTE
Meminta izin dari pengguna
Setelah membuat instance klien, aplikasi Anda perlu meminta izin dari pengguna. Pengguna harus diizinkan untuk memberikan atau menolak izin kapan saja. Untuk melakukannya, buat kumpulan izin untuk jenis data yang diperlukan. Pastikan izin dalam kumpulan dideklarasikan dalam manifes Android Anda terlebih dahulu.
val permissions = setOf( HealthPermission.getReadPermission(ExerciseSessionRecord::class), HealthPermission.getWritePermission(ExerciseSessionRecord::class) )
getGrantedPermissions
untuk mengetahui apakah aplikasi Anda sudah mendapatkan izin yang diperlukan. Jika belum, gunakan
createRequestPermissionResultContract
untuk meminta izin tersebut. Tindakan ini akan menampilkan layar izin Health Connect.
val permissions = setOf( HealthPermission.getReadPermission(StepsRecord::class), HealthPermission.getWritePermission(StepsRecord::class), HealthPermission.getReadPermission(HeartRateRecord::class), HealthPermission.getWritePermission(HeartRateRecord::class) ) val requestPermissionsLauncher = rememberLauncherForActivityResult( contract = PermissionController.createRequestPermissionResultContract() ) { grantedPermissions -> if (grantedPermissions.containsAll(permissions)) { coroutineScope.launch { snackbarHostState.showSnackbar("Permissions granted!") } } else { coroutineScope.launch { snackbarHostState.showSnackbar("Permissions denied.") } } }
Informasi yang disertakan dalam kumpulan data sesi latihan
Setiap data sesi latihan berisi informasi berikut:
- Jenis latihan, misalnya, bersepeda.
- Rute latihan, yang berisi informasi seperti lintang, bujur, dan ketinggian.
Agregasi yang didukung
Nilai gabungan berikut tersedia untuk
ExerciseSessionRecord:
Contoh penggunaan
Cuplikan kode berikut menunjukkan cara membaca dan menulis rute olahraga.
Baca rute olahraga
Aplikasi Anda tidak dapat membaca data rute latihan yang dibuat oleh aplikasi lain saat berjalan di latar belakang.
Saat aplikasi Anda berjalan di latar belakang dan mencoba membaca rute latihan yang dibuat
oleh aplikasi lain, Health Connect akan menampilkan respons ExerciseRouteResult.ConsentRequired, meskipun aplikasi Anda memiliki akses Selalu izinkan ke data rute
latihan.
Oleh karena itu, sebaiknya Anda meminta rute setelah interaksi pengguna yang disengaja dengan aplikasi Anda, saat pengguna berinteraksi secara aktif dengan UI aplikasi Anda.
Untuk mempelajari lebih lanjut pembacaan latar belakang, lihat Contoh pembacaan latar belakang.
Cuplikan kode berikut menunjukkan cara membaca sesi di Health Connect dan meminta rute dari sesi tersebut:
private suspend fun readExerciseSessionAndRoute() { val client = healthConnectClient ?: return val endTime = Instant.now() val startTime = endTime.minus(Duration.ofHours(1)) val grantedPermissions = client.permissionController.getGrantedPermissions() // 1. Verify basic Exercise Session permissions if (!grantedPermissions.contains( HealthPermission.getReadPermission(ExerciseSessionRecord::class) ) ) { return } // 2. Read the sessions val readResponse = client.readRecords( ReadRecordsRequest( ExerciseSessionRecord::class, TimeRangeFilter.between(startTime, endTime) ) ) val exerciseRecord = readResponse.records.firstOrNull() ?: return val recordId = exerciseRecord.metadata.id // 3. Read the specific record to check for the route val sessionResponse = client.readRecord(ExerciseSessionRecord::class, recordId) // 4. Handle the Route Result directly from the response when (val routeResult = sessionResponse.record.exerciseRouteResult) { is ExerciseRouteResult.Data -> { displayExerciseRoute(routeResult.exerciseRoute) } is ExerciseRouteResult.ConsentRequired -> { // Since you are in a Service, you cannot launch ActivityResultLauncher. // Send a notification to the user to grant route-specific consent. handleConsentRequired(recordId) } is ExerciseRouteResult.NoData -> Unit else -> Unit } } private fun displayExerciseRoute(route: ExerciseRoute) { val locations = route.route.orEmpty() for (location in locations) { println(location) } }
Menulis rute latihan
Kode berikut menunjukkan cara merekam sesi yang menyertakan rute olahraga:
private suspend fun insertExerciseRoute() { val client = healthConnectClient ?: return val grantedPermissions = client.permissionController.getGrantedPermissions() // 1. Verify Session Write Permission val hasWriteSession = grantedPermissions.contains( HealthPermission.getWritePermission(ExerciseSessionRecord::class) ) if (!hasWriteSession) return val sessionStartTime = Instant.now() val sessionDuration = Duration.ofMinutes(20) val sessionEndTime = sessionStartTime.plus(sessionDuration) // 2. Build the route if route-specific write permission is granted val hasWriteRoute = grantedPermissions.contains(HealthPermission.PERMISSION_WRITE_EXERCISE_ROUTE) val exerciseRoute = if (hasWriteRoute) { ExerciseRoute( listOf( ExerciseRoute.Location( time = sessionStartTime, latitude = 6.5483, longitude = 0.5488, horizontalAccuracy = Length.meters(2.0), verticalAccuracy = Length.meters(2.0), altitude = Length.meters(9.0), ), ExerciseRoute.Location( time = sessionEndTime.minusSeconds(1), latitude = 6.4578, longitude = 0.6577, horizontalAccuracy = Length.meters(2.0), verticalAccuracy = Length.meters(2.0), altitude = Length.meters(9.2), ) ) ) } else { null } // 3. Create the session record val exerciseSessionRecord = ExerciseSessionRecord( startTime = sessionStartTime, startZoneOffset = ZoneOffset.UTC, endTime = sessionEndTime, endZoneOffset = ZoneOffset.UTC, exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_BIKING, title = "Morning Bike Ride", exerciseRoute = exerciseRoute, metadata = Metadata.activelyRecorded( device = Device(type = Device.TYPE_PHONE) ) ) // 4. Insert into Health Connect client.insertRecords(listOf(exerciseSessionRecord)) }
Sesi olahraga
Sesi olahraga dapat mencakup apa saja, dari berlari hingga bulu tangkis.
Menulis sesi olahraga
Berikut ini cara mem-build permintaan penyisipan yang menyertakan sesi:
suspend fun writeExerciseSession(healthConnectClient: HealthConnectClient) {
healthConnectClient.insertRecords(
listOf(
ExerciseSessionRecord(
startTime = START_TIME,
startZoneOffset = START_ZONE_OFFSET,
endTime = END_TIME,
endZoneOffset = END_ZONE_OFFSET,
exerciseType = ExerciseSessionRecord.ExerciseType.RUNNING,
title = "My Run",
metadata = Metadata.manualEntry()
),
// ... other records
)
)
}
Membaca sesi olahraga
Berikut ini contoh cara membaca sesi olahraga:
suspend fun readExerciseSessions(
healthConnectClient: HealthConnectClient,
startTime: Instant,
endTime: Instant
) {
val response =
healthConnectClient.readRecords(
ReadRecordsRequest(
ExerciseSessionRecord::class,
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
for (exerciseRecord in response.records) {
// Process each exercise record
// Optionally pull in with other data sources of the same time range.
val distanceRecord =
healthConnectClient
.readRecords(
ReadRecordsRequest(
DistanceRecord::class,
timeRangeFilter =
TimeRangeFilter.between(
exerciseRecord.startTime,
exerciseRecord.endTime
)
)
)
.records
}
}
Menulis data subjenis
Sesi juga dapat terdiri dari data subjenis opsional yang memperkaya sesi dengan informasi tambahan.
Misalnya, sesi olahraga dapat menyertakan class ExerciseSegment, ExerciseLap,
dan ExerciseRoute:
val segments = listOf(
ExerciseSegment(
startTime = Instant.parse("2022-01-02T10:10:10Z"),
endTime = Instant.parse("2022-01-02T10:10:13Z"),
segmentType = ActivitySegmentType.BENCH_PRESS,
repetitions = 373
)
)
val laps = listOf(
ExerciseLap(
startTime = Instant.parse("2022-01-02T10:10:10Z"),
endTime = Instant.parse("2022-01-02T10:10:13Z"),
length = 0.meters
)
)
ExerciseSessionRecord(
exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_CALISTHENICS,
startTime = Instant.parse("2022-01-02T10:10:10Z"),
endTime = Instant.parse("2022-01-02T10:10:13Z"),
startZoneOffset = ZoneOffset.UTC,
endZoneOffset = ZoneOffset.UTC,
segments = segments,
laps = laps,
route = route,
metadata = Metadata.manualEntry()
)
Menghapus sesi olahraga
Ada dua cara untuk menghapus sesi olahraga:
- Menurut rentang waktu.
- Menurut UID.
Berikut ini cara menghapus data subjenis berdasarkan rentang waktu:
suspend fun deleteExerciseSessionByTimeRange( healthConnectClient: HealthConnectClient, exerciseRecord: ExerciseSessionRecord, ) { val timeRangeFilter = TimeRangeFilter.between(exerciseRecord.startTime, exerciseRecord.endTime) healthConnectClient.deleteRecords(ExerciseSessionRecord::class, timeRangeFilter) // delete the associated distance record healthConnectClient.deleteRecords(DistanceRecord::class, timeRangeFilter) }
Anda juga dapat menghapus data subjenis menurut UID. Melakukan hal tersebut hanya akan menghapus sesi olahraga, bukan data terkait:
suspend fun deleteExerciseSessionByUid( healthConnectClient: HealthConnectClient, exerciseRecord: ExerciseSessionRecord, ) { healthConnectClient.deleteRecords( ExerciseSessionRecord::class, recordIdsList = listOf(exerciseRecord.metadata.id), clientRecordIdsList = emptyList() ) }