如果應用程式需要在背景監控健康照護服務資料,就適合採用被動資料更新。此功能是針對跨數小時、數天或更長時間的用途設計。如果您需要在應用程式未運作、使用者並未明顯處於運動狀態時儲存或處理健康資料,則請使用健康照護服務的被動用戶端。
如需被動資料使用範例,請參閱 被動資料 和 被動目標 範例。
新增依附元件
如要為健康照護服務新增依附元件,必須將 Google Maven 存放區新增至專案。詳情請參閱「Google 的 Maven 存放區」。
請在模組層級 build.gradle
檔案中新增以下依附元件:
Groovy
dependencies { implementation "androidx.health:health-services-client:1.1.0-alpha03" }
Kotlin
dependencies { implementation("androidx.health:health-services-client:1.1.0-alpha03") }
檢查功能
在註冊資料更新前,請確認裝置可以提供指定類型 所需資料您可以利用檢查作業啟用/停用特定功能或修改應用程式的 UI,彌補未提供的功能。
val healthClient = HealthServices.getClient(this /*context*/)
val passiveMonitoringClient = healthClient.passiveMonitoringClient
lifecycleScope.launchWhenCreated {
val capabilities = passiveMonitoringClient.capabilities.await()
// Supported types for passive data collection
supportsHeartRate =
DataType.HEART_RATE_BPM in capabilities.supportedDataTypesPassiveMonitoring
// Supported types for PassiveGoals
supportsStepsGoal =
DataType.STEPS_DAILY in capabilities.supportedDataTypesPassiveGoals
}
註冊被動資料
您可以透過服務和/或回呼接收被動資料。當應用程式的任何部分未顯示於前景時,應用程式可以利用服務在背景接收資料。背景接收資料作業是採分批進行。相較之下,回呼功能接收資料的速度更快一些,但僅適用於應用程式運作且成功通知回呼的情況。
無論您使用何種方法,請先建立 PassiveListenerConfig
決定要接收的資料類型,如以下範例所示:
val passiveListenerConfig = PassiveListenerConfig.builder()
.setDataTypes(setOf(DataType.HEART_RATE_BPM))
.build()
如要使用回呼功能接收資料,請定義並註冊回呼,如以下範例所示:
val passiveListenerCallback: PassiveListenerCallback = object : PassiveListenerCallback {
override fun onNewDataPointsReceived(dataPoints: DataPointContainer) {
// TODO: Do something with dataPoints
}
}
passiveMonitoringClient.setPassiveListenerCallback(
passiveListenerConfig,
passiveListenerCallback
)
// To remove the listener
passiveMonitoringClient.clearPassiveListenerCallbackAsync()
服務的使用方式與回呼類似,但此時不應建立從 PassiveListenerCallback
衍生的類別,而是要從 PassiveListenerService
衍生,如以下範例所示:
class PassiveDataService : PassiveListenerService() {
override fun onNewDataPointsReceived(dataPoints: DataPointContainer) {
// TODO: Do something with dataPoints
}
}
passiveMonitoringClient.setPassiveListenerServiceAsync(
PassiveDataService::class.java,
passiveListenerConfig
)
接著,請在 AndroidManifest.xml
檔案中聲明服務。您需具備健康照護服務權限,確保只有健康照護服務可以繫結至該服務:
<service android:name=".PassiveDataService"
android:permission="com.google.android.wearable.healthservices.permission.PASSIVE_DATA_BINDING"
android:exported="true" />
解譯時間
從健康照護服務接收資料時會分批進行,因此可能會在同一批次中收到不同類型的資料點,或收到相同類型的多個資料點。使用這些物件中包含的時間戳記 (而非應用程式收到的時間),以便判斷事件的正確順序。
您可以先計算啟動時間戳記,然後取得各個 DataPoint
的時間戳記,如以下範例所示:
val bootInstant =
Instant.ofEpochMilli(System.currentTimeMillis() - SystemClock.elapsedRealtime())
這個值隨後可以傳遞至 getStartInstant()
或 getEndInstant()
。
在啟動後恢復註冊申請
重新啟動後,系統不會保留被動資料註冊。如要在裝置重新啟動後接收資料,請使用會監聽 ACTION_BOOT_COMPLETED
系統廣播訊息的 BroadcastReceiver
重新建立註冊。
在接收端中,請勿嘗試直接還原註冊,而是應將這項功能委派給 WorkManager
worker。裝置啟動時,健康照護服務可能需要 10 秒以上時間才能確認被動資料註冊要求,這可能會超過 BroadcastReceiver
允許的執行時間。相比之下,WorkManager
worker 的執行時間上限為 10 分鐘。
下列程式碼片段為 BroadcastReceiver
的示例:
class StartupReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != Intent.ACTION_BOOT_COMPLETED) return
// TODO: Check permissions first
WorkManager.getInstance(context).enqueue(
OneTimeWorkRequestBuilder<RegisterForPassiveDataWorker>().build()
)
}
}
class RegisterForPassiveDataWorker(
private val appContext: Context,
workerParams: WorkerParameters
) : Worker(appContext, workerParams) {
override fun doWork(): Result {
runBlocking {
HealthServices.getClient(appContext)
.passiveMonitoringClient
.setPassiveListenerCallback(...)
}
return Result.success()
}
}
如要安排系統在裝置啟動時執行此程式碼,請對 AndroidManifest.xml
檔案進行兩項變更。
首先,請將下列權限新增為 <manifest>
的子項:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
接著,將下列接收器意圖篩選器新增為 <application>
的子項:
<receiver
android:name=".StartupReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
活動狀態
被動用戶端也可以提供使用者狀態的概略資訊,例如是否正在睡眠。如要接收這類更新,請按照下列步驟操作:
- 要求
ACTIVITY_RECOGNITION
權限。 - 在
PassiveListenerConfig
建構工具中呼叫setShouldUserActivityInfoBeRequested(true)
。
建議您在回呼或服務中覆寫 onUserActivityInfoReceived()
方法,並使用傳回的 UserActivityInfo
,如以下範例所示:
override fun onUserActivityInfoReceived(info: UserActivityInfo) {
val stateChangeTime: Instant = info.stateChangeTime // may be in the past!
val userActivityState: UserActivityState = info.userActivityState
if (userActivityState == UserActivityState.USER_ACTIVITY_ASLEEP) {
// ...
}
}
被動目標
您可以設定被動用戶端在達到被動目標時通知應用程式,例如使用者在一天內走完 10,000 步時。
如要執行此操作,請設定目標,如以下範例所示:
val dailyStepsGoal by lazy {
val condition = DataTypeCondition(
dataType = DataType.STEPS_DAILY,
threshold = 10_000, // Trigger every 10000 steps
comparisonType = ComparisonType.GREATER_THAN_OR_EQUAL
)
PassiveGoal(condition)
}
將這個目標加入 PassiveListenerConfig
,如以下範例所示:
val passiveListenerConfig = PassiveListenerConfig.builder()
.setDailyGoals(setOf(dailyStepsGoal))
.build()
請在回呼或服務中覆寫 onGoalCompleted()
方法,並使用傳回的 PassiveGoal
,如以下範例所示:
override fun onGoalCompleted(goal: PassiveGoal) {
when (goal.dataTypeCondition.dataType) {
DataType.STEPS_DAILY -> {
// ...
}
}
}