Bu kılavuz, Health Connect'in 1.1.0-alpha11 sürümüyle uyumludur.
Health Connect, antrenman uygulamalarının antrenman planları yazmasına ve antrenman uygulamalarının antrenman planlarını okumasına olanak tanıyan bir planlı egzersiz veri türü sağlar. Kaydedilen egzersizler (antrenmanlar), kullanıcıların antrenman hedeflerine ulaşmasına yardımcı olmak için kişiselleştirilmiş performans analizi amacıyla tekrar okunabilir.
Özellik kullanılabilirliği
Kullanıcının cihazının Health Connect'te antrenman planlarını destekleyip desteklemediğini belirlemek için istemcideFEATURE_PLANNED_EXERCISE
simgesinin 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 Özelliklerin kullanılabilirliğini kontrol etme başlıklı makaleyi inceleyin.
Gerekli izinler
Planlanmış egzersize erişim aşağıdaki izinlerle korunur:
android.permission.health.READ_PLANNED_EXERCISE
android.permission.health.WRITE_PLANNED_EXERCISE
Uygulamanıza planlı egzersiz özelliği eklemek için öncelikle PlannedExerciseSession
veri türü için yazma izni isteyerek başlayın.
Planlı egzersiz yazabilmek için beyan etmeniz gereken izin aşağıda verilmiştir:
<application>
<uses-permission
android:name="android.permission.health.WRITE_PLANNED_EXERCISE" />
...
</application>
Planlanan egzersizi okumak için aşağıdaki izinleri istemeniz gerekir:
<application>
<uses-permission
android:name="android.permission.health.READ_PLANNED_EXERCISE" />
...
</application>
Kullanıcıdan izin isteme
İstemci örneği oluşturduktan sonra uygulamanızın kullanıcıdan izin istemesi gerekir. Kullanıcıların izinleri istedikleri zaman vermesine veya reddetmesine izin verilmelidir.
Bunun için gerekli veri türleri için bir izin grubu oluşturun. Gruptaki izinlerin önce Android manifestinizde tanımlandığından emin olun.
// Create a set of permissions for required data types
val PERMISSIONS =
setOf(
HealthPermission.getReadPermission(HeartRateRecord::class),
HealthPermission.getWritePermission(HeartRateRecord::class),
HealthPermission.getReadPermission(PlannedExerciseSessionRecord::class),
HealthPermission.getWritePermission(PlannedExerciseSessionRecord::class),
HealthPermission.getReadPermission(ExerciseSessionRecord::class),
HealthPermission.getWritePermission(ExerciseSessionRecord::class)
)
Uygulamanıza gerekli izinlerin verilip verilmediğini görmek için getGrantedPermissions
aracını kullanın. Aksi takdirde, bu izinleri istemek için createRequestPermissionResultContract
simgesini kullanın. Bu işlem, Health Connect izinleri ekranını gösterir.
// Create the permissions launcher
val requestPermissionActivityContract = PermissionController.createRequestPermissionResultContract()
val requestPermissions = registerForActivityResult(requestPermissionActivityContract) { granted ->
if (granted.containsAll(PERMISSIONS)) {
// Permissions successfully granted
} else {
// Lack of required permissions
}
}
suspend fun checkPermissionsAndRun(healthConnectClient: HealthConnectClient) {
val granted = healthConnectClient.permissionController.getGrantedPermissions()
if (granted.containsAll(PERMISSIONS)) {
// Permissions already granted; proceed with inserting or reading data
} else {
requestPermissions.launch(PERMISSIONS)
}
}
Kullanıcılar izinleri istedikleri zaman verebilir veya iptal edebilir. Bu nedenle, uygulamanızın verilen izinleri düzenli olarak kontrol etmesi ve izinlerin kaybedildiği senaryoları yönetmesi gerekir.
İlgili izinler
Eğitim planları egzersiz oturumlarına bağlanır. Bu nedenle, kullanıcının Health Connect'in bu özelliğini tam olarak kullanabilmesi için antrenman planıyla ilgili her kayıt türünün kullanılmasına izin 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 bildirmesi ve kullanıcının bu izinleri vermesi gerekebilir:
android.permission.health.READ_EXERCISE
android.permission.health.READ_EXERCISE_ROUTES
android.permission.health.READ_HEART_RATE
android.permission.health.WRITE_EXERCISE
android.permission.health.WRITE_EXERCISE_ROUTE
android.permission.health.WRITE_HEART_RATE
Ancak, eğitim planları oluşturan ve performansı planlara göre değerlendiren uygulama genellikle eğitim 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 izinleri gerekli olmayabilir. Ö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_ROUTES |
WRITE_EXERCISE_ROUTE |
READ_HEART_RATE |
WRITE_HEART_RATE |
Planlanmış egzersiz oturumu kaydında yer alan bilgiler
- Oturumun başlığı.
- Planlanmış egzersiz bloklarının listesi.
- Oturumun başlangıç ve bitiş zamanı.
- Egzersiz türü.
- Etkinlikle ilgili notlar.
- Meta veri
- Tamamlanan egzersiz oturumu kimliği: Bu, planlanan egzersiz oturumuyla ilgili bir egzersiz oturumu tamamlandıktan sonra otomatik olarak yazılır.
Planlanmış egzersiz bloğu kaydında yer alan bilgiler
Planlanmış bir egzersiz bloğu, farklı adım gruplarının tekrarını desteklemek için bir egzersiz adımları listesi içerir (örneğin, kol kıvırma, burpee ve crunch adımlarını beş kez tekrarlayın).
- Bloğun açıklaması.
- Planlanan egzersiz adımlarının listesi.
- Tekrar sayısı.
Planlanmış egzersiz adımı kaydında yer alan bilgiler
- Adımın açıklaması.
- Egzersiz kategorisi.
- Egzersiz türü
- Performans hedeflerinin listesi.
- Tamamlama hedefi.
Desteklenen toplamalar
Bu veri türü için desteklenen toplama işlemi yok.
Ö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 sayısı 90-110 arasında olacak şekilde gölün etrafında üç tur atılacak.
- Aşağıdakileri içeren planlanmış bir egzersiz oturumu, kullanıcı tarafından bir eğitim planı uygulamasında tanımlanır:
- Çalışmanın planlanan başlangıç ve bitiş zamanı
- Egzersiz türü (koşu)
- Tur sayısı (tekrarlar)
- Nabız için performans hedefi (90 ile 110 nabız/dk. arasında)
- Bu bilgiler egzersiz blokları ve adımlar halinde gruplandırılır ve antrenman planı uygulaması tarafından Health Connect'e
PlannedExerciseSessionRecord
olarak yazılır. - Kullanıcı, planlanan oturumu (koşu) gerçekleştirir.
- Oturumla ilgili egzersiz verileri şu şekilde kaydedilir:
- Oturum sırasında giyilebilir bir cihazla. Örneğin, nabız.
Bu veriler, aktivitenin kayıt türü olarak Health Connect'e yazılır. Bu durumda,
HeartRateRecord
. - Oturumdan sonra kullanıcı tarafından manuel olarak. Örneğin, gerçek koşunun başlangıcını ve bitişini belirtme. Bu veriler, Health Connect'e
ExerciseSessionRecord
olarak yazılır.
- Oturum sırasında giyilebilir bir cihazla. Örneğin, nabız.
Bu veriler, aktivitenin kayıt türü olarak Health Connect'e yazılır. Bu durumda,
- Daha sonra, antrenman planı uygulaması, planlanan egzersiz oturumunda kullanıcı tarafından belirlenen hedeflere karşı gerçek performansı değerlendirmek için Health Connect'teki verileri okur.
Egzersiz planlama ve hedef 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 planlıyor. Bu koşuda, 90-110 nabız/dk. hedef nabız aralığında bir gölün etrafında üç tur koşulacak.
Buna benzer bir snippet, planlanan egzersiz oturumlarını Health Connect'e kaydeden bir uygulamanın form işleyicisinde bulunabilir. Ayrıca, eğitim sunan bir hizmetle entegrasyon gibi durumlarda alım noktasında da bulunabilir.
// Verify 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 = ExerciseSegment.EXERCISE_SEGMENT_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,
metadata = Metadata.manualEntry(
device = Device(type = Device.Companion.TYPE_PHONE)
)
)
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 oturumu olarak yaz.
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 günlüğe kaydedebilen bir giyilebilir cihazın veri alımı ve dışa aktarma işleyicilerinde de bulunabilir.
Buradaki insertedPlannedExerciseSessionId
, önceki örnekten tekrar kullanılmıştır. Gerçek bir uygulamada, kimlik, kullanıcının mevcut oturumlar listesinden planlanmış bir egzersiz oturumu seçmesiyle belirlenir.
// Verify 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,
metadata = Metadata.manualEntry(
device = Device(type = Device.Companion.TYPE_PHONE)
)
)
val insertedExerciseSessions =
healthConnectClient.insertRecords(listOf(exerciseSessionRecord))
Ayrıca, giyilebilir cihaz koşu boyunca kullanıcının nabzını kaydeder. Aşağıdaki snippet, hedef aralıkta kayıt oluşturmak için kullanılabilir.
Gerçek bir uygulamada, bu snippet'in temel parçaları, bir kol saatinden gelen bir mesajın işleyicisinde bulunabilir. Bu işleyici, toplama işleminden sonra ölçümü Health Connect'e yazar.
// Verify 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,
metadata = Metadata.autoRecorded(
device = Device(type = Device.Companion.TYPE_WATCH)
)
)
val insertedHeartRateRecords = healthConnectClient.insertRecords(listOf(heartRateRecord))
Performans hedeflerini değerlendirme
Kullanıcının egzersizinden sonraki gün, kaydedilen egzersizi alabilir, planlanan egzersiz hedeflerini kontrol edebilir ve belirlenen hedeflerin karşılanıp karşılanmadığını belirlemek için ek veri türlerini değerlendirebilirsiniz.
Buna benzer bir snippet, performans hedeflerini değerlendirmek için düzenli olarak yapılan bir işte veya bir egzersiz listesi yüklenirken ve bir uygulamada performans hedefleriyle ilgili bir bildirim gösterilirken bulunabilir.
// Verify 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
}
}
}
}
}
}
}
}
Egzersiz seansları
Egzersiz seansları koşudan badmintona kadar her şeyi içerebilir.
Egzersiz oturumlarını yazma
Oturum içeren bir ekleme isteği oluşturmak için şu adımları uygulayın:
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"
),
// ... other records
)
)
}
Egzersiz oturumunu okuma
Aşağıda, egzersiz oturumunun nasıl okunacağına dair bir örnek verilmiştir:
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
}
}
Alt tür verilerini yazma
Oturumlar, oturuma ek bilgiler ekleyerek zenginleştiren isteğe bağlı alt tür verilerinden de oluşabilir.
Örneğin, egzersiz oturumları ExerciseSegment
, ExerciseLap
ve ExerciseRoute
sınıflarını içerebilir:
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
)