Mengembangkan Pengalaman Olahraga dengan Health Connect

Jika ingin membuat pengalaman latihan di aplikasi, Anda dapat menggunakan Health Connect untuk melakukan hal-hal seperti:

  • Menulis sesi latihan
  • Tulis rute olahraga
  • Menulis metrik latihan seperti detak jantung, kecepatan, dan jarak
  • Membaca data latihan dari aplikasi lain

Panduan ini menjelaskan cara membuat fitur olahraga ini, yang mencakup jenis data, eksekusi latar belakang, izin, alur kerja yang direkomendasikan, dan praktik terbaik.

Ringkasan: Membuat Pelacak Latihan Komprehensif

Anda dapat membuat pengalaman pelacakan olahraga yang komprehensif menggunakan Health Connect dengan mengikuti langkah-langkah inti berikut:

  • Menerapkan izin dengan benar berdasarkan Izin Kesehatan.
  • Merekam sesi menggunakan ExerciseSessionRecord.
  • Menulis data olahraga secara konsisten selama sesi.
  • Mengelola eksekusi latar belakang dengan benar untuk memverifikasi pengambilan data berkelanjutan.
  • Membaca data sesi untuk ringkasan dan analisis pasca-latihan.

Alur kerja ini memungkinkan interoperabilitas dengan aplikasi Health Connect lainnya dan memverifikasi akses data yang dikontrol pengguna.

Sebelum memulai

Sebelum menerapkan fitur olahraga:

Konsep utama

Health Connect menampilkan data latihan menggunakan beberapa komponen inti. ExerciseSessionRecord bertindak sebagai catatan pusat untuk olahraga, yang berisi detail seperti waktu mulai atau waktu berakhir dan jenis olahraga. Selama sesi, berbagai jenis data seperti HeartRateRecord atau SpeedRecord dapat direkam. Untuk aktivitas di luar ruangan, ExerciseRoute menyimpan data GPS, yang ditautkan ke sesi yang sesuai.

Sesi olahraga

ExerciseSessionRecord adalah catatan pusat untuk data olahraga, yang mewakili satu sesi olahraga. Setiap catatan menyimpan:

  • startTime
  • endTime
  • exerciseType
  • Metadata sesi opsional (judul, catatan)

ExerciseSessionRecord juga dapat berisi rute latihan, putaran, dan segmen sebagai bagian dari datanya. Selain itu, jenis data lain seperti HeartRateRecord atau SpeedRecord dapat direkam selama sesi dan dikaitkan dengannya.

Jenis data terkait

Data yang terkait dengan sesi olahraga diwakili oleh jenis catatan individual. Jenis yang umum meliputi:

Untuk daftar lengkap jenis data, lihat Jenis data Health Connect.

Rute olahraga

Anda dapat mengaitkan rute dengan latihan di luar ruangan menggunakan ExerciseRoute. Rute terdiri dari objek ExerciseRoute.Location berurutan yang masing-masing berisi:

  • Lintang dan bujur
  • Ketinggian opsional
  • Bearing opsional
  • Informasi akurasi
  • Stempel waktu

Menautkan rute sesi

ExerciseRoute berisi data lokasi berurutan untuk sesi latihan. Data ini tidak diperlakukan sebagai catatan independen di Health Connect. Sebagai gantinya, Anda memberikan data ExerciseRoute saat menyisipkan atau memperbarui ExerciseSessionRecord.

Pertimbangan pengembangan

Aplikasi pelacakan latihan sering kali perlu berjalan dalam waktu yang lama, sering kali di latar belakang saat layar mati. Saat membuat fitur latihan, penting untuk mempertimbangkan cara mengelola eksekusi latar belakang dan meminta izin yang diperlukan untuk data latihan.

Eksekusi latar belakang

Aplikasi latihan biasanya berjalan dengan layar mati. Saat dalam status ini, Anda harus menggunakan:

  • Layanan latar depan untuk pengambilan sampel lokasi dan sensor
  • WorkManager untuk penulisan atau sinkronisasi yang ditangguhkan
  • Strategi batch untuk penulisan catatan reguler

Pertahankan kontinuitas dengan menjaga ID sesi tetap konsisten di semua penulisan.

Izin

Aplikasi Anda harus meminta izin Health Connect yang relevan sebelum membaca atau menulis data latihan. Izin umum untuk latihan mencakup sesi latihan, rute latihan, dan metrik seperti detak jantung atau kecepatan. Ini mencakup hal-hal berikut:

  • Sesi latihan: Izin baca dan tulis untuk ExerciseSessionRecord.
  • Rute latihan: Izin baca dan tulis untuk ExerciseRoute.
  • Detak jantung: Izin baca dan tulis untuk HeartRateRecord.
  • Kecepatan: Izin baca dan tulis untuk SpeedRecord.
  • Jarak: Izin baca dan tulis untuk DistanceRecord.
  • Kalori: Izin baca dan tulis untuk TotalCaloriesBurnedRecord.
  • Ketinggian yang diperoleh: Izin baca dan tulis untuk ElevationGainedRecord.
  • Langkah per menit: Izin baca dan tulis untuk StepsCadenceRecord.
  • Daya: Izin baca dan tulis untuk PowerRecord.
  • Langkah: Izin baca dan tulis untuk StepsRecord.

Berikut contoh cara meminta beberapa izin untuk sesi latihan yang mencakup data rute, detak jantung, jarak, kalori, kecepatan, dan langkah:

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),
        HealthPermission.getReadPermission(HeartRateRecord::class),
        HealthPermission.getWritePermission(HeartRateRecord::class),
        HealthPermission.getReadPermission(SpeedRecord::class),
        HealthPermission.getWritePermission(SpeedRecord::class),
        HealthPermission.getReadPermission(DistanceRecord::class),
        HealthPermission.getWritePermission(DistanceRecord::class),
        HealthPermission.getReadPermission(TotalCaloriesBurnedRecord::class),
        HealthPermission.getWritePermission(TotalCaloriesBurnedRecord::class),
        HealthPermission.getReadPermission(StepsRecord::class),
        HealthPermission.getWritePermission(StepsRecord::class)
    )
Gunakan 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.") }
    }
}
Karena pengguna dapat memberikan atau mencabut izin kapan saja, aplikasi Anda perlu memeriksa izin setiap kali sebelum menggunakannya dan menangani skenario saat izin hilang.

Untuk meminta izin, panggil fungsi checkPermissionsAndRun:

if (!granted.containsAll(permissions)) {
    // Check if required permissions are not granted, and return
    return emptySet()
}
// Permissions already granted; proceed with inserting or reading data

Jika Anda hanya perlu meminta izin untuk satu jenis data, seperti detak jantung, sertakan hanya jenis data tersebut dalam kumpulan izin Anda:

Akses ke detak jantung dilindungi oleh izin berikut:

  • android.permission.health.READ_HEART_RATE
  • android.permission.health.WRITE_HEART_RATE

Untuk menambahkan kemampuan detak jantung ke aplikasi Anda, mulailah dengan meminta izin untuk jenis data HeartRateRecord.

Berikut adalah izin yang harus Anda deklarasikan agar dapat menulis detak jantung:

<application>
  <uses-permission
android:name="android.permission.health.WRITE_HEART_RATE" />
...
</application>

Untuk membaca detak jantung, Anda harus meminta izin berikut:

<application>
  <uses-permission
android:name="android.permission.health.READ_HEART_RATE" />
...
</application>

Menerapkan sesi latihan

Bagian ini menjelaskan alur kerja yang direkomendasikan untuk merekam data latihan.

Memulai sesi

Untuk membuat latihan baru:

  1. Buat ID sesi unik: Pastikan ID ini stabil. Jika proses aplikasi Anda dihentikan dan dimulai ulang, Anda harus dapat melanjutkan menggunakan ID yang sama untuk mencegah sesi yang terfragmentasi.
  2. Tetapkan metadata.clientRecordId untuk mencegah duplikat selama percobaan ulang sinkronisasi.
  3. Tulis ExerciseSessionRecord: Sertakan waktu mulai.
  4. Mulai kumpulkan Jenis data dan data GPS: Hanya mulai setelah catatan sesi berhasil diinisialisasi.

Contoh:

val sessionClientId = UUID.randomUUID().toString()
val zoneOffset = ZoneOffset.systemDefault().rules.getOffset(startTime)

val session =   ExerciseSessionRecord(
    startTime = startTime,
    startZoneOffset = zoneOffset,
    endTime = startTime.plusSeconds(3600),
    endZoneOffset = zoneOffset,
    exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_RUNNING,
    metadata = Metadata(clientRecordId = sessionClientId),
)

healthConnectClient.insertRecords(listOf(session))

Merekam rute latihan

Untuk mempelajari panduan membaca lebih lanjut, lihat Membaca data mentah.

Saat merekam rute latihan, Anda harus membuat batch data. Artinya, alih-alih menyimpan setiap titik GPS satu per satu saat terjadi, Anda mengumpulkan sekelompok titik dan menyimpannya sekaligus dalam satu panggilan.

Hal ini penting karena setiap kali aplikasi Anda membaca atau menulis ke Health Connect, aplikasi tersebut menggunakan sedikit daya baterai dan daya pemrosesan.

Kode berikut menunjukkan cara merekam dalam batch:

// 1. Create a list to hold your route locations
val routeLocations = mutableListOf<ExerciseRoute.Location>()

// 2. Add points to your list as the exercise happens
routeLocations.add(
    ExerciseRoute.Location(
        time = Instant.now(),
        latitude = 37.7749,
        longitude = -122.4194
    )
)

// ... keep adding points over a period of time ...

// 3. Save the whole list at once (Batching)
val session = ExerciseSessionRecord(
    startTime = startTime,
    endTime = endTime,
    exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_RUNNING,
    // We pass the whole list here
    exerciseRoute = ExerciseRoute(routeLocations)
)

healthConnectClient.insertRecords(listOf(session))

Mengakhiri sesi

Setelah menghentikan pengumpulan data:

  • Perbarui catatan: Aplikasi Anda memperbarui ExerciseSessionRecord dengan endTime.
  • Selesaikan data: Secara opsional, hitung nilai ringkasan (seperti total jarak atau kecepatan rata-rata) dan tulis sebagai catatan tambahan.
val finishedSession = session.copy(endTime = Instant.now())
healthConnectClient.updateRecords(listOf(finishedSession))

Membaca data latihan

Aplikasi dapat membaca sesi latihan dan data terkaitnya untuk meringkas aktivitas, memberikan insight kesehatan, atau menyinkronkan data dengan server eksternal. Misalnya, Anda dapat membaca ExerciseSessionRecord, lalu membuat kueri HeartRateRecord atau DistanceRecord yang terjadi selama interval waktu yang sama.

Jika Anda perlu menyinkronkan data latihan dengan server backend, atau menjaga datastore aplikasi tetap terbaru dengan Health Connect, gunakan ChangeLogs. Hal ini memungkinkan Anda mengambil daftar catatan yang disisipkan, diperbarui, atau dihapus sejak titik waktu tertentu, yang lebih efisien daripada melacak perubahan secara manual atau berulang kali membaca semua data. Untuk mengetahui informasi selengkapnya, lihat Menyinkronkan data dengan Health Connect.

Membaca sesi

Untuk membaca sesi latihan, gunakan ReadRecordsRequest dengan ExerciseSessionRecord sebagai jenisnya. Anda biasanya memfilter ini berdasarkan rentang waktu tertentu.

suspend fun readExerciseSessions(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    val response = healthConnectClient.readRecords(
        ReadRecordsRequest(
            recordType = ExerciseSessionRecord::class,
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
        )
    )

    for (exerciseRecord in response.records) {
        // Process each session
        val exerciseType = exerciseRecord.exerciseType
        val notes = exerciseRecord.notes
    }
}

Membaca rute

Meskipun data ExerciseRoute ditulis sebagai bagian dari sesi latihan, data tersebut harus dibaca secara terpisah. Gunakan metode getExerciseRoute() dengan ID sesi untuk membaca data rutenya:

suspend fun readExerciseRoute(
    healthConnectClient: HealthConnectClient,
    exerciseSessionRecord: ExerciseSessionRecord
) {
    // Check if the session has a route
    val route = healthConnectClient.getExerciseRoute(
        exerciseSessionRecordId = exerciseSessionRecord.metadata.id
    )

    when (route) {
        is ExerciseRouteResponse.Success -> {
            val locations = route.exerciseRoute.locations
            for (location in locations) {
                // Use latitude, longitude, and altitude
            }
        }
        is ExerciseRouteResponse.NoData -> {
            // Handle case where no route exists
        }
        is ExerciseRouteResponse.ConsentRequired -> {
            // Handle case where permissions are missing
        }
    }
}

Membaca jenis data

Untuk membaca data terperinci tertentu (seperti detak jantung) yang terjadi selama sesi, gunakan startTime dan endTime sesi untuk memfilter permintaan jenis data tersebut.

suspend fun readHeartRateData(
    healthConnectClient: HealthConnectClient,
    exerciseSession: ExerciseSessionRecord
) {
    val response = healthConnectClient.readRecords(
        ReadRecordsRequest(
            recordType = HeartRateRecord::class,
            timeRangeFilter = TimeRangeFilter.between(
                exerciseSession.startTime,
                exerciseSession.endTime
            )
        )
    )

    for (heartRateRecord in response.records) {
        for (sample in heartRateRecord.samples) {
            val bpm = sample.beatsPerMinute
        }
    }
}

Praktik terbaik

Ikuti panduan ini untuk meningkatkan keandalan data dan pengalaman pengguna:

  • Menulis secara berkala selama pelacakan aktif: Untuk pelacakan aktif, tulis data saat tersedia atau pada interval maksimum 15 menit.
  • Menggunakan WorkManager untuk sinkronisasi latar belakang: Gunakan WorkManager untuk penulisan yang ditangguhkan. Targetkan interval 15 menit untuk menyeimbangkan antara data real-time dan efisiensi baterai.
  • Membuat batch permintaan tulis: Jangan menulis setiap peristiwa sensor satu per satu. Buat permintaan Anda dalam beberapa bagian. Health Connect menangani hingga 1.000 catatan per permintaan tulis.
  • Menjaga ID sesi tetap stabil dan unik: Gunakan ID yang konsisten untuk sesi Anda. Jika sesi diedit atau diperbarui, penggunaan ID yang sama akan mencegah sesi tersebut diperlakukan sebagai sesi baru yang terpisah.
  • Menggunakan batch untuk jenis data dan titik rute: Untuk mengurangi overhead Input/Output dan menghemat masa pakai baterai, kelompokkan titik data Anda ke dalam satu panggilan insertRecords, bukan menulis setiap titik satu per satu.
  • Menghindari penulisan data duplikat: Menggunakan ID Klien: Saat membuat catatan, tetapkan metadata.clientRecordId. Health Connect menggunakan ID ini untuk mengidentifikasi catatan unik. Jika Anda mencoba menulis catatan dengan clientRecordId yang sudah ada, Health Connect akan mengabaikan duplikat atau memperbarui catatan yang ada, bukan membuat catatan baru. Menetapkan metadata.clientRecordId adalah cara paling efektif untuk mencegah duplikat selama percobaan ulang sinkronisasi atau penginstalan ulang aplikasi.
    val record = StepsRecord(
        count = 100,
        startTime = startTime,
        endTime = endTime,
        startZoneOffset = ZoneOffset.UTC,
        endZoneOffset = ZoneOffset.UTC,
        metadata = Metadata(
            // Use a unique ID from your own database
            clientRecordId = "daily_steps_2023_10_27_user_123"
        )
    )
  • Memeriksa data yang ada: Sebelum menyinkronkan, kueri rentang waktu untuk melihat apakah catatan dari aplikasi Anda sudah ada.
  • Memvalidasi akurasi GPS: Filter sampel GPS dengan akurasi rendah (Misalnya, titik dengan radius akurasi horizontal yang tinggi) sebelum menulis ke ExerciseRoute untuk memverifikasi bahwa peta terlihat bersih dan profesional.
  • Memastikan stempel waktu tidak tumpang tindih: Pastikan sesi baru tidak dimulai sebelum sesi sebelumnya berakhir. Sesi yang tumpang tindih dapat menyebabkan konflik di dasbor kebugaran dan perhitungan ringkasan.
  • Memberikan alasan yang jelas untuk izin: Gunakan alur Permission.createIntent untuk menjelaskan alasan aplikasi Anda memerlukan akses ke data kesehatan, misalnya: 'Untuk memantau tren tekanan darah Anda dan memberikan insight.'
  • Mendukung jeda dan lanjutkan: Pastikan aplikasi Anda menangani jeda dengan benar. Saat pengguna menjeda, hentikan pengumpulan titik rute dan jenis data sehingga kecepatan dan durasi rata-rata tetap akurat.
  • Menguji sesi yang berjalan lama: Pantau konsumsi baterai selama sesi yang berlangsung beberapa jam untuk memverifikasi bahwa interval batch dan penggunaan sensor tidak menguras baterai perangkat.
  • Menyelaraskan stempel waktu dengan frekuensi sensor: Cocokkan stempel waktu catatan Anda dengan frekuensi sensor yang sebenarnya untuk mempertahankan data dengan fidelitas tinggi.

Pengujian

Untuk memverifikasi kebenaran data dan pengalaman pengguna berkualitas tinggi, ikuti strategi pengujian ini dan lihat dokumentasi resmi Menguji kasus penggunaan teratas.

Alat verifikasi

  • Toolbox Health Connect: Gunakan aplikasi pendamping ini untuk memeriksa catatan secara manual, menghapus data pengujian, dan menyimulasikan perubahan pada database. Ini adalah cara terbaik untuk memverifikasi bahwa catatan Anda disimpan dengan benar.
  • Pengujian unit dengan FakeHealthConnectClient: Gunakan library pengujian untuk memverifikasi cara aplikasi Anda menangani kasus ekstrem, seperti pencabutan izin atau pengecualian API tanpa memerlukan perangkat fisik.

Checklist kualitas

Arsitektur umum

Implementasi olahraga biasanya mencakup:

Komponen Mengelola
Pengontrol sesi Status sesi
Timer
Logika batch
Pengontrol jenis data
Pengambilan sampel lokasi
Lapisan repositori (membungkus operasi Health Connect:) Menyisipkan sesi
Menyisipkan jenis data
Menyisipkan titik rute
Membaca ringkasan sesi
Lapisan UI (Menampilkan): Durasi
Jenis data langsung
Pratinjau peta
Perhitungan terpisah
Trace GPS Langsung

Pemecahan masalah

Gejala Kemungkinan penyebab Resolusi
Rute tidak terkait dengan sesi ID sesi atau rentang waktu tidak cocok. Pastikan ExerciseRoute ditulis dengan rentang waktu yang sepenuhnya berada dalam durasi ExerciseSessionRecord. Pastikan Anda menggunakan ID yang konsisten jika mereferensikan sesi nanti. Lihat Merekam rute latihan.
Jenis data tidak ada (misalnya, Detak Jantung) Izin tulis tidak ada atau filter waktu salah. Pastikan Anda telah meminta dan pengguna telah memberikan izin jenis data tertentu. Pastikan ReadRecordsRequest Anda menggunakan TimeRangeFilter yang cocok dengan sesi. Lihat Izin.
Sesi gagal ditulis Stempel waktu tumpang tindih. Health Connect dapat menolak catatan yang tumpang tindih dengan data yang ada dari aplikasi yang sama. Pastikan startTime sesi baru berada setelah endTime sesi sebelumnya.
Tidak ada data GPS yang direkam Layanan latar depan dihentikan atau tidak aktif. Untuk mengumpulkan data saat layar mati, Anda harus menggunakan Layanan Latar Depan dengan atribut foregroundServiceType="health" atau lokasi.
Catatan duplikat muncul clientRecordId tidak ada. Tetapkan clientRecordId unik di Metadata setiap catatan. Hal ini memungkinkan Health Connect melakukan penghapusan duplikat jika data yang sama ditulis dua kali selama percobaan ulang sinkronisasi. Lihat Praktik terbaik.

Langkah-langkah umum untuk proses debug

Periksa status izin. Selalu panggil getPermissionStatus() sebelum mencoba operasi baca atau tulis. Pengguna dapat mencabut izin di setelan sistem kapan saja.
Verifikasi mode eksekusi. Jika aplikasi Anda tidak mengumpulkan data di latar belakang, pastikan Anda telah mendeklarasikan izin yang benar dalam file AndroidManifest.xml dan pengguna belum menempatkan aplikasi ke mode "Baterai Dibatasi".