Verileri arka planda izleme

Pasif veri güncellemeleri, Sağlık Hizmetleri verilerini arka planda izlemesi gereken uygulamalar için uygundur. Saatler, günler veya daha uzun süreyi kapsayan kullanım alanları için tasarlanmıştır. Uygulamanız çalışmıyorken sağlık verilerini depolamanız veya işlemeniz gerekiyorsa ve kullanıcı açık bir şekilde egzersiz yapmadıysa Health Service'in pasif istemcisini kullanın.

Pasif veri kullanımı örnekleri için GitHub'daki Pasif Veri ve Pasif Hedefler örneklerini inceleyin.

Bağımlılık ekleme

Sağlık Hizmetleri'nde bağımlılık eklemek için projenize Google Maven deposunu eklemeniz gerekir. Daha fazla bilgi için Google'ın Maven deposuna bakın.

Modül düzeyindeki build.gradle dosyanıza aşağıdaki bağımlılığı ekleyin:

Modern

dependencies {
    implementation "androidx.health:health-services-client:1.1.0-alpha02"
}

Kotlin

dependencies {
    implementation("androidx.health:health-services-client:1.1.0-alpha02")
}

Özellikleri kontrol edin

Veri güncellemelerine kaydolmadan önce cihazın, uygulamanızın ihtiyaç duyduğu veri türünü sağlayıp sağlayamayacağını kontrol edin. Özellikleri kontrol etmek, belirli özellikleri etkinleştirmenize veya devre dışı bırakmanıza veya uygulamanızın kullanıcı arayüzünü, kullanılamayan özellikleri karşılayacak şekilde değiştirmenize olanak tanır.

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
}

Pasif verilere kaydolma

Pasif verileri bir hizmet, geri arama veya her ikisi üzerinden alabilirsiniz. Hizmet, uygulamanızın hiçbir bölümü ön planda görünür olmadığında uygulamanızın arka planda veri almasını sağlar. Veriler arka planda geldiğinde gruplar hâlinde iletilir. Geri çağırma, verileri biraz daha yüksek bir hızda alır, ancak bu yalnızca uygulama çalışırken ve geri çağırma başarıyla bildirilirken ortaya çıkar.

Hangi yöntemi kullanırsanız kullanın, önce aşağıdaki örnekte gösterildiği gibi, hangi veri türlerini alacağınızı belirleyen bir PassiveListenerConfig oluşturun:

val passiveListenerConfig = PassiveListenerConfig.builder()
    .setDataTypes(setOf(DataType.HEART_RATE_BPM))
    .build()

Geri çağırma yöntemini kullanarak veri almak için geri çağırmayı aşağıdaki örnekte gösterildiği gibi tanımlayıp kaydedin:

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

Hizmet kullanımı da benzerdir, ancak PassiveListenerCallback öğesinden türetilen bir sınıf oluşturmak yerine aşağıdaki örnekte gösterildiği gibi PassiveListenerService parametresinden türetin:

class PassiveDataService : PassiveListenerService() {
    override fun onNewDataPointsReceived(dataPoints: DataPointContainer) {
        // TODO: Do something with dataPoints
    }
}

passiveMonitoringClient.setPassiveListenerServiceAsync(
    PassiveDataService::class.java,
    passiveListenerConfig
)

Ardından, AndroidManifest.xml dosyanızda hizmeti beyan edin. Hizmete yalnızca Sağlık Hizmetleri'nin bağlanabilmesini sağlayan Sağlık Hizmetleri iznini gerekli kılın:

<service android:name=".PassiveDataService"
    android:permission="com.google.android.wearable.healthservices.permission.PASSIVE_DATA_BINDING"
    android:exported="true" />

Zamanı yorumlama

Sağlık Hizmetleri'nden aldığınız veriler toplu hale getirilir. Böylece aynı toplu işlemde farklı türlerde veri noktaları veya aynı türde birden fazla veri noktası alabilirsiniz. Etkinliklerin doğru sıralamasını belirlemek için bunların uygulamanız tarafından alındığı zaman yerine bu nesnelerin içinde yer alan zaman damgalarını kullanın.

Aşağıdaki örnekte gösterildiği gibi, önce başlatma zaman damgasını hesaplayarak her DataPoint için zaman damgaları edinin:

val bootInstant =
    Instant.ofEpochMilli(System.currentTimeMillis() - SystemClock.elapsedRealtime())

Bu değer daha sonra getStartInstant() veya getEndInstant() öğesine iletilebilir.

Başlatma sonrasında kayıtları geri yükle

Pasif veri kayıtları, yeniden başlatmalarda devam etmez. Bir cihaz yeniden başlatıldıktan sonra veri almak için ACTION_BOOT_COMPLETED sistem yayınını dinleyen bir BroadcastReceiver kullanarak kayıtlarınızı yeniden oluşturun.

Alıcıda, kayıtları doğrudan geri yüklemeyi denemeyin. Bunun yerine, bu işlev için bir WorkManager çalışanına yetki verin. Cihaz başlatılırken Sağlık Hizmetleri'nin pasif veri kayıt isteğini onaylaması 10 saniye veya daha uzun sürebilir ve bu süre, BroadcastReceiver için izin verilen yürütme süresini aşabilir. Buna karşılık WorkManager çalışanları için 10 dakikalık yürütme sınırı vardır.

Aşağıdaki snippet'te BroadcastReceiver öğesinin nasıl görünebileceği gösterilmektedir:

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

Cihaz başlatıldığında sistemin bu kodu yürütmesini sağlamak için AndroidManifest.xml dosyasında iki değişiklik yapın.

Öncelikle, şu izni <manifest> öğesinin alt öğesi olarak ekleyin:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

İkinci olarak, aşağıdaki alıcı intent filtresini <application> öğesinin alt öğesi olarak ekleyin:

<receiver
    android:name=".StartupReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

Etkinlik durumu

Pasif istemci ayrıca, kullanıcı durumu hakkında (ör. kullanıcının uyuyor olup olmadığı) üst düzey bilgiler sağlayabilir. Bu güncellemeleri almak için şu adımları uygulayın:

  1. ACTIVITY_RECOGNITION iznini isteyin.
  2. PassiveListenerConfig oluşturucuda setShouldUserActivityInfoBeRequested(true) çağırın.

Geri çağırma veya hizmette onUserActivityInfoReceived() yöntemini geçersiz kılın ve döndürülen UserActivityInfo yöntemini aşağıdaki örnekte gösterildiği gibi kullanın:

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) {
        // ...
    }
}

Pasif hedefler

Bir pasif istemciyi, kullanıcının günde 10.000 adımı tamamlaması gibi pasif hedeflere ulaşıldığında uygulamayı bilgilendirecek şekilde yapılandırabilirsiniz.

Bunun için aşağıdaki örnekte gösterildiği gibi bir hedef oluşturun:

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

Bu hedefi aşağıdaki örnekte gösterildiği gibi PassiveListenerConfig kampanyanıza ekleyin:

val passiveListenerConfig = PassiveListenerConfig.builder()
    .setDailyGoals(setOf(dailyStepsGoal))
    .build()

Geri çağırma veya hizmette onGoalCompleted() yöntemini geçersiz kılın ve döndürülen PassiveGoal yöntemini aşağıdaki örnekte gösterildiği gibi kullanın:

override fun onGoalCompleted(goal: PassiveGoal) {
    when (goal.dataTypeCondition.dataType) {
        DataType.STEPS_DAILY -> {
            // ...
        }
    }
}