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ünü 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.
Health Connect'in kullanılabilirliğini kontrol etme
Uygulamanız, Health Connect'i kullanmaya çalışmadan önce kullanıcının cihazında Health Connect'in kullanılabilir olduğunu doğrulamalıdır. Health Connect bazı cihazlarda önceden yüklenmemiş veya devre dışı bırakılmış olabilir.
HealthConnectClient.getSdkStatus() yöntemini kullanarak kullanılabilirliği kontrol edebilirsiniz.
Health Connect'in kullanılıp kullanılamadığını kontrol etme
fun checkHealthConnectAvailability(context: Context) { val providerPackageName = "com.google.android.apps.healthdata" // Or get from HealthConnectClient.DEFAULT_PROVIDER_PACKAGE_NAME 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 }
getSdkStatus() tarafından döndürülen duruma bağlı olarak, gerekirse kullanıcıyı Google Play Store'dan Health Connect'i yüklemeye veya güncellemeye yönlendirebilirsiniz.
Ö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
}
Gerekli izinler
Planlanmış egzersize erişim aşağıdaki izinlerle korunur:
android.permission.health.READ_PLANNED_EXERCISEandroid.permission.health.WRITE_PLANNED_EXERCISE
Uygulamanıza planlı egzersiz özelliği eklemek için öncelikle PlannedExerciseSession veri türü için izin isteğinde bulunun.
Planlı egzersiz yazabilmek için beyan etmeniz gereken izin şudur:
<application>
<uses-permission
android:name="android.permission.health.WRITE_PLANNED_EXERCISE" />
...
</application>
Planlanmış 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 isteyin
İ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.
Bunu yapmak için gerekli veri türleri için bir dizi izin oluşturun. Gruptaki izinlerin önce Android manifestinizde beyan edildiğinden 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 seçeneğini 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 izinleri kullanmadan önce her seferinde kontrol etmeli ve izinlerin kaybedildiği senaryoları ele almalıdır.
İlgili izinler
Eğitim planları egzersiz oturumlarına bağlıdı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 nabız hızını ölçüyorsa egzersiz oturumunu yazmak ve sonuçları daha sonra değerlendirmek için geliştiricinin aşağıdaki izinleri tanımlaması ve kullanıcının bu izinleri vermesi gerekebilir:
android.permission.health.READ_EXERCISEandroid.permission.health.READ_EXERCISE_ROUTESandroid.permission.health.READ_HEART_RATEandroid.permission.health.WRITE_EXERCISEandroid.permission.health.WRITE_EXERCISE_ROUTEandroid.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ı | Antrenman 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 hareketlerini beş kez art arda yapı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 kalp atış hızı 90 ile 110 bpm arasında olan bir 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
PlannedExerciseSessionRecordolarak 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 cihaz tarafından. Ö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
ExerciseSessionRecordolarak yazılır.
- Oturum sırasında giyilebilir bir cihaz tarafından. Ö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, hedef kalp atış hızı 90-110 bpm olacak şekilde gölün etrafında üç tur atılacak.
Bu gibi bir snippet, planlanmış 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 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ük kaydı yapabilen 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))
Giyilebilir bir cihaz, koşu boyunca nabzı da 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 giyilebilir cihazdan 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 antrenmanından 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 oturumları koşudan badmintona kadar çeşitli aktiviteleri içerebilir.
Egzersiz oturumlarını yazma
Oturum içeren bir kampanya siparişi 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",
metadata = Metadata.manualEntry()
),
// ... 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,
metadata = Metadata.manualEntry()
)