שירותי הבריאות מספקים תמיכה באפליקציות לאימונים באמצעות ExerciseClient
.
באמצעות ExerciseClient
, האפליקציה יכולה לשלוט מתי מתבצע אימון, להוסיף יעדי אימון ולקבל עדכונים לגבי מצב האימון, אירועי אימון או מדדים אחרים. למידע נוסף, אפשר לעיין ברשימה המלאה של סוגי התרגילים ששירותי הבריאות תומכים בהם.
אפשר לעיין בדוגמה לתרגיל ב-GitHub.
הוספת יחסי תלות
כדי להוסיף תלות ב-Health Services, צריך להוסיף את מאגר Google Maven לפרויקט. מידע נוסף זמין במאמר בנושא מאגר Maven של Google.
לאחר מכן, בקובץ build.gradle
ברמת המודול, מוסיפים את התלות הבאה:
Groovy
dependencies { implementation "androidx.health:health-services-client:1.1.0-alpha05" }
Kotlin
dependencies { implementation("androidx.health:health-services-client:1.1.0-alpha05") }
מבנה האפליקציה
כשמפתחים אפליקציית אימון באמצעות Health Services, כדאי להשתמש במבנה האפליקציה הבא:
- מומלץ לשמור את המסכים והניווט בתוך פעילות ראשית.
- ניהול מצב האימון, נתוני החיישן, הפעילות השוטפת והנתונים באמצעות שירות חזיתי.
- אחסון נתונים באמצעות Room, והעלאת נתונים באמצעות WorkManager.
כשמתכוננים לאימון ובמהלך האימון, יכול להיות שהפעילות תיפסק מסיבות שונות. יכול להיות שהמשתמש יעבור לאפליקציה אחרת או יחזור לתצוגת השעון. יכול להיות שהמערכת תציג משהו מעל הפעילות שלכם, או שהמסך ייכבה אחרי תקופה של חוסר פעילות.
כדי לוודא שהמדידה תהיה מדויקת לאורך כל האימון, מומלץ להשתמש בForegroundService
שפועל ברציפות בשילוב עם ExerciseClient
.
באמצעות ForegroundService
אפשר להשתמש בOngoing Activity API כדי להציג אינדיקטור בממשקי השעון, וכך לאפשר למשתמש לחזור במהירות לאימון.
חשוב מאוד לבקש נתוני מיקום בצורה נכונה בשירות הפעיל. בקובץ המניפסט, מציינים את סוגי השירותים שפועלים בחזית ואת ההרשאות הנדרשות:
<manifest ...> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <application ...> <!-- If your app is designed only for devices that run Wear OS 4 or lower, use android:foregroundServiceType="location" instead. --> <service android:name=".MyExerciseSessionRecorder" android:foregroundServiceType="health|location"> </service> </application> </manifest>
משתמשים ב-AmbientLifecycleObserver
לפעילות שלפני האימון, שמכילה את הקריאה prepareExercise()
, ולפעילות האימון. עם זאת, לא מומלץ לעדכן את התצוגה במהלך האימון במצב סביבה: הסיבה לכך היא ש-Health Services מעבד את נתוני האימון בקבוצות כשהמסך של המכשיר במצב סביבה כדי לחסוך בחשמל, ולכן המידע שמוצג עשוי להיות לא עדכני. במהלך אימונים, הצגת נתונים שרלוונטיים למשתמש, או הצגת מידע עדכני או מסך ריק.
בדיקת היכולות
כל ExerciseType
תומך בסוגי נתונים מסוימים של מדדים ויעדי פעילות גופנית. חשוב לבדוק את היכולות האלה בהפעלה, כי הן עשויות להשתנות בהתאם למכשיר. יכול להיות שמכשיר מסוים לא תומך בסוג מסוים של פעילות גופנית, או שהוא לא תומך בפונקציה ספציפית, כמו הפסקה אוטומטית. בנוסף, יכול להיות שהיכולות של מכשיר ישתנו עם הזמן, למשל אחרי עדכון תוכנה.
בזמן הפעלת האפליקציה, שולחים שאילתה לגבי היכולות של המכשיר, ומאחסנים ומעבדים את הנתונים הבאים:
- התרגילים שהפלטפורמה תומכת בהם.
- התכונות שנתמכות בכל תרגיל.
- סוגי הנתונים שנתמכים בכל תרגיל.
- ההרשאות שנדרשות לכל אחד מסוגי הנתונים האלה.
אפשר להשתמש ב-ExerciseCapabilities.getExerciseTypeCapabilities()
עם סוג הפעילות שבחרתם כדי לראות אילו מדדים אפשר לבקש, אילו יעדים לפעילות אפשר להגדיר ואילו תכונות אחרות זמינות לסוג הפעילות הזה. כך זה נראה בדוגמה הבאה:
val healthClient = HealthServices.getClient(this /*context*/)
val exerciseClient = healthClient.exerciseClient
lifecycleScope.launch {
val capabilities = exerciseClient.getCapabilitiesAsync().await()
if (ExerciseType.RUNNING in capabilities.supportedExerciseTypes) {
runningCapabilities =
capabilities.getExerciseTypeCapabilities(ExerciseType.RUNNING)
}
}
בתוך ExerciseTypeCapabilities
,
supportedDataTypes
מופיעים סוגי הנתונים שאפשר לבקש לגביהם נתונים. ההגדרה הזו משתנה בהתאם למכשיר, לכן חשוב לא לבקש DataType
שלא נתמך, אחרת הבקשה עלולה להיכשל.
משתמשים בשדות supportedGoals
ו-supportedMilestones
כדי לקבוע אם אפשר להשתמש בתרגיל כדי להשיג את יעד התרגיל שרוצים ליצור.
אם האפליקציה מאפשרת למשתמש להשתמש בהשהיה אוטומטית, אתם צריכים לבדוק אם המכשיר תומך בפונקציונליות הזו באמצעות supportsAutoPauseAndResume
.
ExerciseClient
דוחה בקשות שלא נתמכות במכשיר.
בדוגמה הבאה נבדקת התמיכה בסוג הנתונים HEART_RATE_BPM
, ביכולת המטרה STEPS_TOTAL
ובפונקציית ההשהיה האוטומטית:
// Whether we can request heart rate metrics.
supportsHeartRate = DataType.HEART_RATE_BPM in runningCapabilities.supportedDataTypes
// Whether we can make a one-time goal for aggregate steps.
val stepGoals = runningCapabilities.supportedGoals[DataType.STEPS_TOTAL]
supportsStepGoals =
(stepGoals != null && ComparisonType.GREATER_THAN_OR_EQUAL in stepGoals)
// Whether auto-pause is supported.
val supportsAutoPause = runningCapabilities.supportsAutoPauseAndResume
הרשמה לקבלת עדכונים על מצב האימון
עדכונים לגבי התרגיל נשלחים למאזין. אפשר לרשום באפליקציה רק מאזין אחד בכל פעם. מגדירים את ה-listener לפני שמתחילים את האימון, כמו בדוגמה הבאה. המאזין מקבל עדכונים רק לגבי תרגילים שהאפליקציה שלכם היא הבעלים שלהם.
val callback = object : ExerciseUpdateCallback {
override fun onExerciseUpdateReceived(update: ExerciseUpdate) {
val exerciseStateInfo = update.exerciseStateInfo
val activeDuration = update.activeDurationCheckpoint
val latestMetrics = update.latestMetrics
val latestGoals = update.latestAchievedGoals
}
override fun onLapSummaryReceived(lapSummary: ExerciseLapSummary) {
// For ExerciseTypes that support laps, this is called when a lap is marked.
}
override fun onAvailabilityChanged(
dataType: DataType<*, *>,
availability: Availability
) {
// Called when the availability of a particular DataType changes.
when {
availability is LocationAvailability -> // Relates to Location/GPS.
availability is DataTypeAvailability -> // Relates to another DataType.
}
}
}
exerciseClient.setUpdateCallback(callback)
ניהול משך הפעילות
שירותי הבריאות תומכים באימון אחד לכל היותר בכל האפליקציות במכשיר. אם מתבצע מעקב אחרי פעילות גופנית ואפליקציה אחרת מתחילה לעקוב אחרי פעילות גופנית חדשה, הפעילות הראשונה מסתיימת.
לפני שמתחילים את התרגיל, צריך לבצע את הפעולות הבאות:
- בודקים אם כבר מתבצע מעקב אחרי פעילות גופנית, ומגיבים בהתאם. לדוגמה, אפשר לבקש מהמשתמש אישור לפני שמבטלים תרגיל קודם ומתחילים לעקוב אחרי תרגיל חדש.
בדוגמה הבאה אפשר לראות איך בודקים אם יש תרגיל קיים באמצעות getCurrentExerciseInfoAsync
:
lifecycleScope.launch {
val exerciseInfo = exerciseClient.getCurrentExerciseInfoAsync().await()
when (exerciseInfo.exerciseTrackedStatus) {
OTHER_APP_IN_PROGRESS -> // Warn user before continuing, will stop the existing workout.
OWNED_EXERCISE_IN_PROGRESS -> // This app has an existing workout.
NO_EXERCISE_IN_PROGRESS -> // Start a fresh workout.
}
}
הרשאות
כשמשתמשים ב-ExerciseClient
, חשוב לוודא שהאפליקציה מבקשת את ההרשאות הנדרשות ושומרת עליהן.
אם האפליקציה שלכם משתמשת בנתוני LOCATION
, חשוב לוודא שהאפליקציה מבקשת את ההרשאות המתאימות לשימוש בנתונים האלה ושומרת אותן.
לפני שמפעילים את הפונקציות prepareExercise()
או startExercise()
, צריך לבצע את הפעולות הבאות לכל סוגי הנתונים:
- מציינים את ההרשאות המתאימות לסוגי הנתונים המבוקשים בקובץ
AndroidManifest.xml
. - מוודאים שהמשתמש העניק את ההרשאות הנדרשות. מידע נוסף זמין במאמר בנושא בקשת הרשאות לאפליקציה. אם ההרשאות הנדרשות לא ניתנו כבר, Health Services דוחה את הבקשה.
כדי להוסיף נתוני מיקום, מבצעים את השלבים הבאים:
- בודקים ש-GPS מופעל במכשיר באמצעות
isProviderEnabled(LocationManager.GPS_PROVIDER)
. אם צריך, מבקשים מהמשתמש לפתוח את הגדרות המיקום. - חשוב לוודא ש
ForegroundService
עםforegroundServiceType
מתאים נשמר לאורך כל האימון.
הכנה לאימון
יכול להיות שייקח זמן קצר עד שחלק מהחיישנים, כמו GPS או דופק, יתחממו, או שהמשתמש ירצה לראות את הנתונים שלו לפני תחילת האימון. השיטה האופציונלית prepareExerciseAsync()
מאפשרת לחיישנים האלה להתחמם ולקבל נתונים בלי להפעיל את הטיימר של האימון. זמן ההכנה הזה לא משפיע על activeDuration
.
לפני שמתקשרים אל prepareExerciseAsync()
, חשוב לבדוק את הדברים הבאים:
בודקים את הגדרת המיקום בכל הפלטפורמה. המשתמש שולט בהגדרה הזו בתפריט ההגדרות הראשי. היא שונה מבדיקת ההרשאות ברמת האפליקציה.
אם ההגדרה מושבתת, צריך להודיע למשתמש שהוא סירב לתת גישה למיקום, ולבקש ממנו להפעיל אותה אם האפליקציה דורשת גישה למיקום.
צריך לוודא שיש לאפליקציה הרשאות בזמן ריצה לחיישני גוף (רמת API 35 ומטה) או לקצב לב (רמת API 36 ומעלה), לזיהוי פעילות ולמיקום מדויק. אם חסרות הרשאות, צריך לבקש מהמשתמש הרשאות בתחילת ההפעלה ולספק הקשר מתאים. אם המשתמש לא מעניק הרשאה ספציפית, צריך להסיר את סוגי הנתונים שמשויכים להרשאה הזו מהקריאה אל
prepareExerciseAsync()
. אם לא ניתנו הרשאות לשימוש בחיישן הגוף (קצב הלב ברמת API 36 ומעלה) או הרשאות למיקום, אל תפעילו אתprepareExerciseAsync()
, כי הפעלת ההכנה מיועדת במיוחד להשגת קצב לב יציב או תיקון GPS לפני תחילת האימון. האפליקציה עדיין יכולה לקבל מדדים כמו מרחק לפי צעדים, קצב, מהירות ומדדים אחרים שלא דורשים את ההרשאות האלה.
כדי לוודא שהשיחה אל prepareExerciseAsync()
תצליח, צריך לבצע את הפעולות הבאות:
- משתמשים ב-
AmbientLifecycleObserver
לפעילות שלפני האימון שמכילה את הקריאה לפעולה 'הכנה'. - מתקשרים אל
prepareExerciseAsync()
מהשירות שפועל בחזית. אם הוא לא נמצא בשירות והוא קשור למחזור החיים של הפעילות, יכול להיות שההכנה של החיישן תופסק שלא לצורך. - כדאי להפעיל את
endExercise()
כדי להשבית את החיישנים ולצמצם את צריכת החשמל אם המשתמש עובר מפעילות שלפני האימון.
בדוגמה הבאה מוצג אופן ההפעלה של prepareExerciseAsync()
:
val warmUpConfig = WarmUpConfig(
ExerciseType.RUNNING,
setOf(
DataType.HEART_RATE_BPM,
DataType.LOCATION
)
)
// Only necessary to call prepareExerciseAsync if body sensor (API level 35
// or lower), heart rate (API level 36+), or location permissions are given.
exerciseClient.prepareExerciseAsync(warmUpConfig).await()
// Data and availability updates are delivered to the registered listener.
אחרי שהאפליקציה עוברת למצב PREPARING
, עדכונים לגבי זמינות החיישנים מועברים בערכים ExerciseUpdateCallback
עד onAvailabilityChanged()
.
אחרי כן המידע הזה יוצג למשתמש כדי שיוכל להחליט אם להתחיל את האימון.
התחלת האימון
כדי להתחיל תרגיל, יוצרים ExerciseConfig
כדי להגדיר את סוג התרגיל, את סוגי הנתונים שרוצים לקבל לגביהם מדדים ואת יעדי התרגיל או אבני הדרך.
יעדי האימון מורכבים מDataType
וממצב. יעדי פעילות גופנית הם יעדים חד-פעמיים שמופעלים כשמתקיים תנאי מסוים, למשל כשמשתמש רץ למרחק מסוים. אפשר גם להגדיר אבן דרך של פעילות גופנית. אפשר להפעיל אבני דרך של פעילות גופנית כמה פעמים, למשל בכל פעם שהמשתמש רץ מעבר למרחק שהוגדר.
בדוגמה הבאה מוצגות הוראות ליצירת יעד אחד מכל סוג:
const val CALORIES_THRESHOLD = 250.0
const val DISTANCE_THRESHOLD = 1_000.0 // meters
suspend fun startExercise() {
// Types for which we want to receive metrics.
val dataTypes = setOf(
DataType.HEART_RATE_BPM,
DataType.CALORIES_TOTAL,
DataType.DISTANCE
)
// Create a one-time goal.
val calorieGoal = ExerciseGoal.createOneTimeGoal(
DataTypeCondition(
dataType = DataType.CALORIES_TOTAL,
threshold = CALORIES_THRESHOLD,
comparisonType = ComparisonType.GREATER_THAN_OR_EQUAL
)
)
// Create a milestone goal. To make a milestone for every kilometer, set the initial
// threshold to 1km and the period to 1km.
val distanceGoal = ExerciseGoal.createMilestone(
condition = DataTypeCondition(
dataType = DataType.DISTANCE_TOTAL,
threshold = DISTANCE_THRESHOLD,
comparisonType = ComparisonType.GREATER_THAN_OR_EQUAL
),
period = DISTANCE_THRESHOLD
)
val config = ExerciseConfig(
exerciseType = ExerciseType.RUNNING,
dataTypes = dataTypes,
isAutoPauseAndResumeEnabled = false,
isGpsEnabled = true,
exerciseGoals = mutableListOf<ExerciseGoal<Double>>(calorieGoal, distanceGoal)
)
exerciseClient.startExerciseAsync(config).await()
}
אפשר גם לסמן הקפות לכל התרגילים. שירותי הבריאות מספקים ExerciseLapSummary
עם מדדים שמצטברים במהלך תקופת ההקפה.
בדוגמה הקודמת השתמשנו ב-isGpsEnabled
, שצריך להיות true כשמבקשים נתוני מיקום. עם זאת, השימוש ב-GPS יכול לעזור גם במדדים אחרים. אם ב-ExerciseConfig
מצוינת מרחק כ-DataType
,
ברירת המחדל היא שימוש בצעדים להערכת המרחק. אם מפעילים את ה-GPS, אפשר להשתמש בנתוני המיקום כדי להעריך את המרחק.
איך משהים אימון, ממשיכים אותו ומסיימים אותו
אפשר להשהות, להמשיך או לסיים אימונים בשיטה המתאימה, למשל
pauseExerciseAsync()
או
endExerciseAsync()
.
השתמש במצב מ-ExerciseUpdate
כמקור האמת. האימון לא נחשב כמושהה כשהקריאה אל pauseExerciseAsync()
חוזרת, אלא כשהמצב הזה משתקף בהודעה ExerciseUpdate
. חשוב במיוחד לקחת את זה בחשבון כשמדובר במצבי ממשק משתמש. אם המשתמש לוחץ על ההשהיה,
משביתים את לחצן ההשהיה ומתקשרים אל pauseExerciseAsync()
בשירותי הבריאות. ממתינים עד שהשירותים בתחום הבריאות יגיעו למצב מושהה באמצעות ExerciseUpdate.exerciseStateInfo.state
, ואז מעבירים את הכפתור למצב הפעלה מחדש. הסיבה לכך היא שעדכוני סטטוס של שירותי הבריאות יכולים להימשך זמן רב יותר מהלחיצה על הלחצן, ולכן אם תקשרו את כל השינויים בממשק המשתמש ללחיצות על הלחצן, יכול להיות שהממשק לא יסתנכרן עם הסטטוס של שירותי הבריאות.
חשוב לזכור את זה במצבים הבאים:
- ההשהיה האוטומטית מופעלת: אפשר להשהות את האימון או להתחיל אותו בלי שהמשתמש יבצע פעולה.
- אפליקציה אחרת מתחילה אימון: יכול להיות שהאימון יסתיים ללא אינטראקציה מצד המשתמש.
אם אפליקציה אחרת מפסיקה את האימון באפליקציה שלכם, האפליקציה שלכם צריכה לטפל בהפסקת האימון בצורה תקינה:
- שמירת מצב האימון החלקי כדי שלא יימחקו נתוני ההתקדמות של המשתמש.
- להסיר את הסמל של הפעילות המתמשכת ולשלוח למשתמש התראה שמיידעת אותו שאפליקציה אחרת סיימה את האימון שלו.
בנוסף, צריך לטפל במקרה שבו ההרשאות מבוטלות במהלך תרגיל מתמשך. הנתון הזה נשלח באמצעות המצב isEnded
, עם ExerciseEndReason
של AUTO_END_PERMISSION_LOST
. צריך לטפל במקרה הזה באופן דומה לטיפול במקרה של סיום: לשמור את המצב החלקי, להסיר את הסמל של פעילות מתמשכת ולשלוח למשתמש התראה לגבי מה שקרה.
בדוגמה הבאה אפשר לראות איך לבדוק אם יש סיום בצורה נכונה:
val callback = object : ExerciseUpdateCallback {
override fun onExerciseUpdateReceived(update: ExerciseUpdate) {
if (update.exerciseStateInfo.state.isEnded) {
// Workout has either been ended by the user, or otherwise terminated
}
...
}
...
}
ניהול משך הפעילות
במהלך אימון, אפליקציה יכולה להציג את משך האימון הפעיל. האפליקציה, שירותי הבריאות ויחידת המיקרו-בקר (MCU) של המכשיר – המעבד בעל צריכת ההספק הנמוכה שאחראי למעקב אחר פעילות גופנית – צריכים להיות מסונכרנים, עם אותו משך פעילות נוכחי. כדי לעזור בניהול הזה, Health Services שולח ActiveDurationCheckpoint
שמספק נקודת התחלה שממנה האפליקציה יכולה להפעיל את הטיימר שלה.
משך הצפייה הפעילה נשלח מה-MCU ויכול לקחת קצת זמן עד שהוא מגיע לאפליקציה, ולכן ActiveDurationCheckpoint
מכיל שתי מאפיינים:
activeDuration
: משך הזמן שהתרגיל פעיל-
time
: מתי חושב משך הזמן הפעיל
לכן, באפליקציה, משך הפעילות של תרגיל יכול להיות מחושב מ-ActiveDurationCheckpoint
באמצעות המשוואה הבאה:
(now() - checkpoint.time) + checkpoint.activeDuration
ההפרש הקטן הזה נובע מהזמן שחולף בין חישוב משך הפעילות הפעילה ב-MCU לבין ההגעה לאפליקציה. אפשר להשתמש בהפרש הזה כדי להגדיר שעון עצר באפליקציה, וכך לוודא שהטיימר באפליקציה מסונכרן באופן מושלם עם השעה בשירותי הבריאות וב-MCU.
אם התרגיל מושהה, האפליקציה מחכה להפעלה מחדש של הטיימר בממשק המשתמש עד שהזמן המחושב חולף מעבר למה שמוצג בממשק המשתמש.
הסיבה לכך היא שאות ההשהיה מגיע לשירותי הבריאות ול-MCU עם עיכוב קל. לדוגמה, אם האפליקציה מושהית בזמן t=10 שניות, יכול להיות ששירותי הבריאות לא יעבירו את העדכון PAUSED
לאפליקציה עד לזמן t=10.2 שניות.
עבודה עם נתונים מ-ExerciseClient
מדדים לסוגי הנתונים שהאפליקציה שלכם נרשמה אליהם מועברים בהודעות של ExerciseUpdate
.
המעבד מעביר הודעות רק כשהוא פעיל או כשמגיע לפרק זמן מקסימלי לדיווח, למשל כל 150 שניות. אל תסתמכו על התדירות ExerciseUpdate
כדי להריץ שעון עצר עם activeDuration
. בדוגמה לתרגיל ב-GitHub אפשר לראות איך מטמיעים שעון עצר עצמאי.
כשמשתמש מתחיל אימון, יכול להיות שExerciseUpdate
הודעות יישלחו בתדירות גבוהה, למשל כל שנייה. כשהמשתמש מתחיל את האימון, יכול להיות שהמסך יכבה. שירותי הבריאות יכולים לספק נתונים בתדירות נמוכה יותר, אבל עדיין לדגום אותם באותה תדירות, כדי למנוע את הפעלת המעבד הראשי. כשהמשתמש מסתכל על המסך, כל הנתונים שנמצאים בתהליך של צירוף לחבילה מועברים מיד לאפליקציה.
שליטה בקצב של יצירת קבוצות
במקרים מסוימים, יכול להיות שתרצו לשלוט בתדירות שבה האפליקציה מקבלת סוגים מסוימים של נתונים כשהמסך כבוי. אובייקט BatchingMode
מאפשר לאפליקציה לשנות את התנהגות ברירת המחדל של העברת נתונים באצווה, כדי לקבל את הנתונים בתדירות גבוהה יותר.
כדי להגדיר את קצב האצווה, מבצעים את השלבים הבאים:
בודקים אם המכשיר תומך בהגדרה הספציפית של
BatchingMode
:// Confirm BatchingMode support to control heart rate stream to phone. suspend fun supportsHrWorkoutCompanionMode(): Boolean { val capabilities = exerciseClient.getCapabilities() return BatchingMode.HEART_RATE_5_SECONDS in capabilities.supportedBatchingModeOverrides }
מציינים שאובייקט
ExerciseConfig
צריך להשתמש ב-BatchingMode
מסוים, כמו שמוצג בקטע הקוד הבא.val config = ExerciseConfig( exerciseType = ExerciseType.WORKOUT, dataTypes = setOf( DataType.HEART_RATE_BPM, DataType.TOTAL_CALORIES ), // ... batchingModeOverrides = setOf(BatchingMode.HEART_RATE_5_SECONDS) )
אפשר גם להגדיר את
BatchingMode
באופן דינמי במהלך האימון, במקום להגדיר התנהגות ספציפית של אצווה שתהיה קבועה לאורך כל האימון:val desiredModes = setOf(BatchingMode.HEART_RATE_5_SECONDS) exerciseClient.overrideBatchingModesForActiveExercise(desiredModes)
כדי למחוק את ההתאמה האישית של
BatchingMode
ולחזור להתנהגות ברירת המחדל, מעבירים קבוצה ריקה אלexerciseClient.overrideBatchingModesForActiveExercise()
.
חותמות זמן
הנקודה בזמן של כל נקודת נתונים מייצגת את משך הזמן מאז הפעלת המכשיר. כדי להמיר את הערך הזה לחותמת זמן, מבצעים את הפעולות הבאות:
val bootInstant =
Instant.ofEpochMilli(System.currentTimeMillis() - SystemClock.elapsedRealtime())
אפשר להשתמש בערך הזה עם getStartInstant()
או getEndInstant()
לכל נקודת נתונים.
דיוק הנתונים
חלק מסוגי הנתונים יכולים לכלול מידע על רמת הדיוק שמשויך לכל נקודת נתונים.
הערך הזה מיוצג במאפיין accuracy
.
אפשר לאכלס את הכיתות HrAccuracy
ו-LocationAccuracy
בסוגי הנתונים HEART_RATE_BPM
ו-LOCATION
, בהתאמה. אם המאפיין accuracy
קיים, אפשר להשתמש בו כדי לקבוע אם כל נקודת נתונים מדויקת מספיק עבור האפליקציה שלכם.
אחסון והעלאה של נתונים
אפשר להשתמש ב-Room כדי לשמור נתונים שמתקבלים מ-Health Services. העלאת הנתונים מתבצעת בסוף התרגיל באמצעות מנגנון כמו Work Manager. כך אפשר לוודא ששיחות הרשת להעלאת הנתונים נדחות עד לסיום התרגיל, וכך לצמצם את צריכת החשמל במהלך התרגיל ולפשט את העבודה.
רשימת בדיקה לאינטגרציה
לפני שמפרסמים את האפליקציה שמשתמשת ב-ExerciseClient
של Health Services, כדאי לעיין ברשימת המשימות הבאה כדי לוודא שחוויית המשתמש לא כוללת בעיות נפוצות. ודאו ש:
- האפליקציה בודקת את היכולות של סוג התרגיל ואת היכולות של המכשיר בכל פעם שהאפליקציה פועלת. כך תוכלו לזהות מתי מכשיר או פעילות מסוימים לא תומכים באחד מסוגי הנתונים שהאפליקציה שלכם צריכה.
- אתם מבקשים את ההרשאות הנדרשות ושומרים עליהן, ומציינים אותן בקובץ המניפסט. לפני ההתקשרות אל
prepareExerciseAsync()
, האפליקציה מוודאת שההרשאות בתחילת ההפעלה הוענקו. - האפליקציה שלך משתמשת ב-
getCurrentExerciseInfoAsync()
כדי לטפל בתרחישים הבאים:- כבר מתבצע מעקב אחרי פעילות גופנית, והאפליקציה שלך מבטלת את הפעילות הקודמת.
- אפליקציה אחרת סיימה את האימון. זה יכול לקרות כשהמשתמש פותח מחדש את האפליקציה ומוצגת לו הודעה שמסבירה שהתרגיל הופסק כי אפליקציה אחרת השתלטה על המכשיר.
- אם אתם משתמשים בנתוני
LOCATION
:- האפליקציה שלך שומרת על
ForegroundService
עםforegroundServiceType
המתאים לאורך כל התרגיל (כולל שיחת ההכנה). - בודקת אם ה-GPS מופעל במכשיר באמצעות
isProviderEnabled(LocationManager.GPS_PROVIDER)
, ומציגה למשתמש הנחיה לפתוח את הגדרות המיקום אם צריך. - בתרחישי שימוש תובעניים, שבהם חשוב מאוד לקבל נתוני מיקום עם זמן אחזור נמוך, כדאי לשקול לשלב את ספק המיקום המשולב (FLP) ולהשתמש בנתונים שלו כתיקון מיקום ראשוני. כשמידע יציב יותר על המיקום זמין מ-Health Services, המערכת משתמשת בו במקום ב-FLP.
- האפליקציה שלך שומרת על
- אם האפליקציה שלכם דורשת העלאת נתונים, כל קריאות הרשת להעלאת נתונים נדחות עד לסיום התרגיל. אחרת, במהלך התרגיל, האפליקציה תבצע את כל קריאות הרשת הנדרשות בצורה חסכונית.
מומלץ
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- עדכונים של נתונים פסיביים
- שירותי בריאות ב-Wear OS
- איך מתחילים לעבוד עם משבצות