Program latihan

Panduan ini kompatibel dengan Health Connect versi 1.1.0-alpha11.

Health Connect menyediakan jenis data olahraga terencana untuk memungkinkan aplikasi pelatihan menulis rencana pelatihan dan memungkinkan aplikasi olahraga membaca rencana pelatihan. Olahraga yang direkam (olahraga) dapat dibaca kembali untuk analisis performa yang dipersonalisasi guna membantu pengguna mencapai sasaran pelatihan mereka.

Ketersediaan fitur

Untuk menentukan apakah perangkat pengguna mendukung rencana latihan di Health Connect, periksa ketersediaan FEATURE_PLANNED_EXERCISE di klien:

if (healthConnectClient
     .features
     .getFeatureStatus(
       HealthConnectFeatures.FEATURE_PLANNED_EXERCISE
     ) == HealthConnectFeatures.FEATURE_STATUS_AVAILABLE) {

  // Feature is available
} else {
  // Feature isn't available
}

Lihat Memeriksa ketersediaan fitur untuk mempelajari lebih lanjut.

Izin yang diperlukan

Akses ke rencana pelatihan dilindungi oleh izin berikut:

  • android.permission.health.READ_PLANNED_EXERCISE
  • android.permission.health.WRITE_PLANNED_EXERCISE

Deklarasikan izin ini di Konsol Play untuk aplikasi Anda, serta dalam manifes aplikasi:

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

Anda bertanggung jawab untuk mendeklarasikan semua izin yang sesuai yang ingin Anda gunakan di perangkat dan aplikasi Anda. Anda juga harus memeriksa apakah setiap izin telah diberikan oleh pengguna sebelum digunakan.

Program latihan ditautkan ke sesi olahraga. Oleh karena itu, pengguna harus memberikan izin untuk menggunakan setiap jenis data yang terkait dengan rencana pelatihan agar dapat menggunakan fitur Health Connect ini sepenuhnya.

Misalnya, jika rencana pelatihan mengukur detak jantung pengguna selama serangkaian lari, izin berikut mungkin perlu dideklarasikan oleh developer dan diberikan oleh pengguna untuk menulis sesi olahraga dan membaca hasilnya untuk evaluasi di lain waktu:

  • android.permission.health.READ_EXERCISE
  • android.permission.health.READ_EXERCISE_ROUTE
  • android.permission.health.READ_HEART_RATE
  • android.permission.health.WRITE_EXERCISE
  • android.permission.health.WRITE_EXERCISE_ROUTE
  • android.permission.health.WRITE_HEART_RATE

Namun, sering kali aplikasi yang membuat rencana latihan dan mengevaluasi performa terhadap rencana tidak sama dengan aplikasi yang menggunakan rencana latihan dan menulis data olahraga yang sebenarnya. Bergantung pada jenis aplikasi, tidak semua izin baca dan tulis akan diperlukan. Misalnya, Anda mungkin hanya memerlukan izin ini untuk setiap jenis aplikasi:

Aplikasi program latihan Aplikasi olahraga
WRITE_PLANNED_EXERCISE READ_PLANNED_EXERCISE
READ_EXERCISE WRITE_EXERCISE
READ_EXERCISE_ROUTE WRITE_EXERCISE_ROUTE
READ_HEART_RATE WRITE_HEART_RATE

Informasi yang disertakan dalam data sesi olahraga terencana

  • Judul sesi.
  • Daftar blok latihan yang direncanakan.
  • Waktu mulai dan berakhir sesi.
  • Jenis latihan.
  • Catatan untuk aktivitas.
  • Metadata.
  • ID sesi olahraga yang telah selesai — ID ini ditulis secara otomatis setelah sesi olahraga yang terkait dengan sesi olahraga yang direncanakan ini selesai.

Informasi yang disertakan dalam data blok latihan terencana

Blok olahraga yang direncanakan berisi daftar langkah olahraga, untuk mendukung pengulangan berbagai kelompok langkah (misalnya, lakukan urutan curl lengan, burpee, dan sit-up lima kali berturut-turut).

Informasi yang disertakan dalam data langkah latihan terencana

Agregasi yang didukung

Tidak ada agregasi yang didukung untuk jenis data ini.

Contoh penggunaan

Misalnya, pengguna merencanakan lari selama 90 menit dua hari dari sekarang. Lari ini akan menampilkan tiga putaran di sekitar danau dengan target detak jantung antara 90 dan 110 bpm.

  1. Sesi latihan terencana dengan hal berikut ditentukan oleh pengguna di aplikasi rencana latihan:
    1. Awal dan akhir lari yang direncanakan
    2. Jenis olahraga (lari)
    3. Jumlah putaran (pengulangan)
    4. Target performa untuk detak jantung (antara 90 dan 110 bpm)
  2. Informasi ini dikelompokkan ke dalam blok dan langkah olahraga, serta ditulis ke Health Connect oleh aplikasi rencana pelatihan sebagai PlannedExerciseSessionRecord.
  3. Pengguna melakukan sesi yang direncanakan (berjalan).
  4. Data olahraga yang terkait dengan sesi dicatat:
    1. Oleh perangkat wearable selama sesi berlangsung. Misalnya, detak jantung. Data ini ditulis ke Health Connect sebagai jenis data untuk aktivitas. Dalam hal ini, HeartRateRecord.
    2. Secara manual oleh pengguna setelah sesi. Misalnya, menunjukkan awal dan akhir operasi yang sebenarnya. Data ini ditulis ke Health Connect sebagai ExerciseSessionRecord.
  5. Pada lain waktu, aplikasi rencana pelatihan akan membaca data dari Health Connect untuk mengevaluasi performa sebenarnya terhadap target yang ditetapkan oleh pengguna dalam sesi olahraga yang direncanakan.

Merencanakan latihan dan menetapkan target

Pengguna dapat merencanakan olahraga mereka di masa mendatang dan menetapkan target. Tulis ini ke Health Connect sebagai sesi olahraga terencana.

Dalam contoh yang dijelaskan di Contoh penggunaan, pengguna merencanakan lari selama 90 menit dua hari dari sekarang. Lari ini akan menampilkan tiga putaran di sekitar danau dengan target detak jantung antara 90 dan 110 bpm.

Cuplikan seperti ini dapat ditemukan di pengendali formulir untuk aplikasi yang mencatat sesi olahraga terencana ke Health Connect. Data ini juga dapat ditemukan di titik transfer untuk integrasi, misalnya dengan layanan yang menawarkan pelatihan.

// Ensure the user has granted all necessary permissions for this task
val grantedPermissions =
    healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.contains(
      HealthPermission.getWritePermission(PlannedExerciseSessionRecord::class))) {
    // The user hasn't granted the app permission to write planned exercise session data.
    return
}

val plannedDuration = Duration.ofMinutes(90)
val plannedStartDate = LocalDate.now().plusDays(2)

val plannedExerciseSessionRecord = PlannedExerciseSessionRecord(
    startDate = plannedStartDate,
    duration = plannedDuration,
    exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_RUNNING,
    blocks = listOf(
        PlannedExerciseBlock(
            repetitions = 1, steps = listOf(
                PlannedExerciseStep(
                    exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_RUNNING,
                    exercisePhase = PlannedExerciseStep.EXERCISE_PHASE_ACTIVE,
                    completionGoal = ExerciseCompletionGoal.RepetitionsGoal(repetitions = 3),
                    performanceTargets = listOf(
                        ExercisePerformanceTarget.HeartRateTarget(
                            minHeartRate = 90.0, maxHeartRate = 110.0
                        )
                    )
                ),
            ), description = "Three laps around the lake"
        )
    ),
    title = "Run at lake",
    notes = null
)
val insertedPlannedExerciseSessions =
    healthConnectClient.insertRecords(listOf(plannedExerciseSessionRecord)).recordIdsList
val insertedPlannedExerciseSessionId = insertedPlannedExerciseSessions.first()

Mencatat data olahraga dan aktivitas

Dua hari kemudian, pengguna mencatat sesi olahraga yang sebenarnya. Tulis ini ke Health Connect sebagai sesi latihan.

Dalam contoh ini, durasi sesi pengguna sama persis dengan durasi yang direncanakan.

Cuplikan berikut dapat ditemukan di pengendali formulir untuk aplikasi yang mencatat sesi olahraga ke Health Connect. Data ini juga dapat ditemukan di pengendali impor dan ekspor data untuk perangkat wearable yang dapat mendeteksi dan mencatat sesi latihan.

insertedPlannedExerciseSessionId di sini digunakan kembali dari contoh sebelumnya. Dalam aplikasi sebenarnya, ID akan ditentukan oleh pengguna yang memilih sesi olahraga yang direncanakan dari daftar sesi yang ada.

// Ensure the user has granted all necessary permissions for this task
val grantedPermissions =
    healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.contains(
      HealthPermission.getWritePermission(ExerciseSessionRecord::class))) {
    // The user doesn't granted the app permission to write exercise session data.
    return
}

val sessionDuration = Duration.ofMinutes(90)
val sessionEndTime = Instant.now()
val sessionStartTime = sessionEndTime.minus(sessionDuration)

val exerciseSessionRecord = ExerciseSessionRecord(
    startTime = sessionStartTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = sessionEndTime,
    endZoneOffset = ZoneOffset.UTC,
    exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_RUNNING,
    segments = listOf(
        ExerciseSegment(
            startTime = sessionStartTime,
            endTime = sessionEndTime,
            repetitions = 3,
            segmentType = ExerciseSegment.EXERCISE_SEGMENT_TYPE_RUNNING
        )
    ),
    title = "Run at lake",
    plannedExerciseSessionId = insertedPlannedExerciseSessionId,
)
val insertedExerciseSessions =
    healthConnectClient.insertRecords(listOf(exerciseSessionRecord))

Perangkat wearable juga mencatat detak jantung mereka selama berlari. Cuplikan berikut dapat digunakan untuk membuat data dalam rentang target.

Dalam aplikasi sebenarnya, bagian utama cuplikan ini mungkin ditemukan di pengendali untuk pesan dari perangkat wearable, yang akan menulis pengukuran ke Health Connect setelah pengumpulan.

// Ensure the user has granted all necessary permissions for this task
val grantedPermissions =
    healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.contains(
      HealthPermission.getWritePermission(HeartRateRecord::class))) {
    // The user doesn't granted the app permission to write heart rate record data.
    return
}

val samples = mutableListOf<HeartRateRecord.Sample>()
var currentTime = sessionStartTime
while (currentTime.isBefore(sessionEndTime)) {
    val bpm = Random.nextInt(21) + 90
    val heartRateRecord = HeartRateRecord.Sample(
        time = currentTime,
        beatsPerMinute = bpm.toLong(),
    )
    samples.add(heartRateRecord)
    currentTime = currentTime.plusSeconds(180)
}

val heartRateRecord = HeartRateRecord(
    startTime = sessionStartTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = sessionEndTime,
    endZoneOffset = ZoneOffset.UTC,
    samples = samples,
)
val insertedHeartRateRecords = healthConnectClient.insertRecords(listOf(heartRateRecord))

Mengevaluasi target performa

Sehari setelah olahraga pengguna, Anda dapat mengambil olahraga yang dicatat, memeriksa target olahraga yang direncanakan, dan mengevaluasi jenis data tambahan untuk menentukan apakah target yang ditetapkan tercapai.

Cuplikan seperti ini kemungkinan akan ditemukan dalam tugas berkala untuk mengevaluasi target performa atau saat memuat daftar latihan dan menampilkan notifikasi tentang target performa di aplikasi.

// Ensure the user has granted all necessary permissions for this task
val grantedPermissions =
     healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.containsAll(
        listOf(
            HealthPermission.getReadPermission(ExerciseSessionRecord::class),
            HealthPermission.getReadPermission(PlannedExerciseSessionRecord::class),
            HealthPermission.getReadPermission(HeartRateRecord::class)
        )
    )
) {
    // The user doesn't granted the app permission to read exercise session record data.
    return
}

val searchDuration = Duration.ofDays(1)
val searchEndTime = Instant.now()
val searchStartTime = searchEndTime.minus(searchDuration)

val response = healthConnectClient.readRecords(
    ReadRecordsRequest<ExerciseSessionRecord>(
        timeRangeFilter = TimeRangeFilter.between(searchStartTime, searchEndTime)
    )
)
for (exerciseRecord in response.records) {
    val plannedExerciseRecordId = exerciseRecord.plannedExerciseSessionId
    val plannedExerciseRecord =
        if (plannedExerciseRecordId == null) null else healthConnectClient.readRecord(
            PlannedExerciseSessionRecord::class, plannedExerciseRecordId
        ).record
    if (plannedExerciseRecord != null) {
        val aggregateRequest = AggregateRequest(
            metrics = setOf(HeartRateRecord.BPM_AVG),
            timeRangeFilter = TimeRangeFilter.between(
                exerciseRecord.startTime, exerciseRecord.endTime
            ),
        )
        val aggregationResult = healthConnectClient.aggregate(aggregateRequest)

        val maxBpm = aggregationResult[HeartRateRecord.BPM_MAX]
        val minBpm = aggregationResult[HeartRateRecord.BPM_MIN]
        if (maxBpm != null && minBpm != null) {
            plannedExerciseRecord.blocks.forEach { block ->
                block.steps.forEach { step ->
                    step.performanceTargets.forEach { target ->
                        when (target) {
                            is ExercisePerformanceTarget.HeartRateTarget -> {
                                val minTarget = target.minHeartRate
                                val maxTarget = target.maxHeartRate
                                if(
                                    minBpm >= minTarget && maxBpm <= maxTarget
                                ) {
                                  // Success!
                                }
                            }
                            // Handle more target types
                            }
                        }
                    }
                }
            }
        }
    }
}