Antrenman planları

Bu kılavuz, Health Connect 1.1.0-alpha11 sürümüyle uyumludur.

Health Connect, antrenman uygulamalarının antrenman planları yazmasına ve egzersiz uygulamalarının antrenman planlarını okumasına olanak tanımak için planlanmış egzersiz veri türü sağlar. Kayıtlı egzersizler (antrenmanlar), kullanıcıların antrenman hedeflerine ulaşmalarına yardımcı olmak için kişiselleştirilmiş performans analizi için tekrar okunabilir.

Özellik kullanılabilirliği

Kullanıcının cihazının Health Connect'teki eğitim planlarını destekleyip desteklemediğini belirlemek için istemcide FEATURE_PLANNED_EXERCISE'nin kullanılabilirliğini kontrol edin:

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

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

Daha fazla bilgi için Özellik kullanılabilirliğini kontrol etme başlıklı makaleyi inceleyin.

Gerekli izinler

Eğitim planlarına erişim aşağıdaki izinlerle korunur:

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

Aşağıdaki izinleri uygulamanız için Play Console'da ve uygulamanızın manifest dosyasında beyan edin:

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

Cihazlarınızda ve uygulamalarınızda kullanmak istediğiniz tüm uygun izinleri belirtme sorumluluğu size aittir. Ayrıca, her iznin kullanımdan önce kullanıcı tarafından verildiğini kontrol etmeniz gerekir.

Eğitim planları egzersiz oturumlarına bağlanır. Bu nedenle, kullanıcının Health Connect'in bu özelliğinden tam olarak yararlanabilmesi için bir eğitim planıyla ilgili her kayıt türünü kullanma izni vermesi gerekir.

Örneğin, bir antrenman planı bir dizi koşu sırasında kullanıcının kalp atış hızını ölçüyorsa egzersiz oturumunu yazmak ve sonuçları daha sonra değerlendirmek için geliştiricinin aşağıdaki izinleri belirtmesi ve kullanıcının bu izinleri vermesi gerekebilir:

  • 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

Ancak genellikle antrenman planları oluşturan ve performansı planlara göre değerlendiren uygulama, antrenman planlarını kullanan ve gerçek egzersiz verilerini yazan uygulamayla aynı değildir. Uygulamanın türüne bağlı olarak, tüm okuma ve yazma izinlerine ihtiyaç duyulmayabilir. Örneğin, her uygulama türü için yalnızca şu izinlere ihtiyacınız olabilir:

Antrenman planı uygulaması Egzersiz uygulaması
WRITE_PLANNED_EXERCISE READ_PLANNED_EXERCISE
READ_EXERCISE WRITE_EXERCISE
READ_EXERCISE_ROUTE WRITE_EXERCISE_ROUTE
READ_HEART_RATE WRITE_HEART_RATE

Planlanmış egzersiz oturumu kaydına dahil edilen bilgiler

  • Oturum başlığı.
  • Planlanmış egzersiz bloklarının listesi.
  • Oturumun başlangıç ve bitiş zamanı.
  • Egzersiz türü.
  • Etkinlikle ilgili notlar.
  • Meta veri
  • Tamamlanmış egzersiz oturumu kimliği: Bu, planlanmış egzersiz oturumuyla ilgili bir egzersiz oturumu tamamlandıktan sonra otomatik olarak yazılır.

Planlanmış egzersiz bloğu kaydına dahil edilen bilgiler

Planlanmış bir egzersiz bloğu, farklı adım gruplarının tekrarını desteklemek için egzersiz adımlarının bir listesini içerir (örneğin, kol bükme, burpee ve mekik hareketlerini arka arkaya beş kez yapın).

Planlanmış egzersiz adımı kaydına dahil edilen bilgiler

Desteklenen toplama işlemleri

Bu veri türü için desteklenen toplama işlemi yoktur.

Örnek kullanım

Bir kullanıcının iki gün sonra 90 dakikalık bir koşu planladığını varsayalım. Bu koşuda, hedef nabız 90 ile 110 arasında olacak şekilde gölün etrafında üç tur atılır.

  1. Bir eğitim planı uygulamasında kullanıcı tarafından aşağıdakileri içeren planlanmış bir egzersiz oturumu tanımlanır:
    1. Çalıştırmanın planlanan başlangıç ve bitiş zamanı
    2. Egzersiz türü (koşu)
    3. Tur sayısı (tekrar sayısı)
    4. Nabız için performans hedefi (90 ile 110 nabız/dk. arasında)
  2. Bu bilgiler, egzersiz blokları ve adımlar halinde gruplandırılır ve eğitim planı uygulaması tarafından PlannedExerciseSessionRecord olarak Health Connect'e yazılır.
  3. Kullanıcı, planlanan oturumu gerçekleştirir (çalışır).
  4. Oturumla ilgili egzersiz verileri aşağıdaki durumlarda kaydedilir:
    1. Oturum sırasında giyilebilir cihazlar tarafından. Örneğin, nabız. Bu veriler, etkinlik için kayıt türü olarak Health Connect'e yazılır. Bu durumda HeartRateRecord.
    2. Oturumdan sonra kullanıcı tarafından manuel olarak. Örneğin, gerçek çalıştırmanın başlangıç ve bitiş zamanını belirtme. Bu veriler Health Connect'e ExerciseSessionRecord olarak yazılır.
  5. Daha sonra eğitim planı uygulaması, planlanan egzersiz oturumunda kullanıcı tarafından belirlenen hedeflere göre gerçek performansı değerlendirmek için Health Connect'teki verileri okur.

Egzersizleri planlama ve hedefler belirleme

Kullanıcılar gelecekteki egzersizlerini planlayabilir ve hedefler belirleyebilir. Bunu Health Connect'e planlanmış egzersiz oturumu olarak yazın.

Kullanım örneği bölümünde açıklanan örnekte, kullanıcı iki gün sonra 90 dakikalık bir koşu planlamaktadır. Bu koşuda, hedef nabız 90 ile 110 arasında olacak şekilde gölün etrafında üç tur atılır.

Planlanmış egzersiz oturumlarını Health Connect'e kaydeden bir uygulamanın form işleyicisinde bu tür bir snippet bulunabilir. Bu, entegrasyonların besleme noktasında (ör. eğitim sunan bir hizmette) da bulunabilir.

// 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()

Egzersiz ve etkinlik verilerini günlüğe kaydetme

İki gün sonra kullanıcı gerçek egzersiz oturumunu kaydeder. Bunu Health Connect'e egzersiz seansı olarak yazın.

Bu örnekte, kullanıcının oturum süresi planlanan süreyle tam olarak eşleşti.

Aşağıdaki snippet, egzersiz oturumlarını Health Connect'e kaydeden bir uygulamanın form işleyicisinde bulunabilir. Ayrıca, egzersiz oturumlarını algılayıp kaydedebilen giyilebilir cihazların veri besleme ve dışa aktarma işleyicilerinde de bulunabilir.

Buradaki insertedPlannedExerciseSessionId, önceki örnekten yeniden kullanılmıştır. Gerçek bir uygulamada kimlik, kullanıcının mevcut oturumların listesinden planlanmış bir egzersiz oturumu seçmesiyle belirlenir.

// 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))

Giyilebilir cihazlar, koşu sırasında nabzı da kaydeder. Aşağıdaki snippet, hedef aralıktaki kayıtları oluşturmak için kullanılabilir.

Gerçek bir uygulamada bu snippet'in birincil parçaları, giyilebilir cihazdan gelen bir ileti için işleyicide bulunabilir. Bu işleyici, ölçüm toplandıktan sonra Health Connect'e yazar.

// 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))

Performans hedeflerini değerlendirme

Kullanıcının antrenmanından sonraki gün, kaydedilen antrenmanı alabilir, planlanmış antrenman hedeflerini kontrol edebilir ve belirlenen hedeflerin karşılayıp karşılanmadığını belirlemek için ek veri türlerini değerlendirebilirsiniz.

Bu tür bir snippet, performans hedeflerini değerlendirmek için yapılan düzenli bir işte veya bir uygulamada alıştırma listesi yüklenirken ve performans hedefleri hakkında bildirim gösterilirken bulunur.

// 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
                            }
                        }
                    }
                }
            }
        }
    }
}