Read aggregated data

Stay organized with collections Save and categorize content based on your preferences.

Aggregating data in Health Connect includes basic aggregations or aggregating data into buckets. The following workflows show you how to do both.

Basic aggregation

To use basic aggregation on your data, use the aggregate function on your HealthConnectClient object. It accepts an AggregateRequest object where you add the metric types and the time range as its parameters. How basic aggregates are called depends on the metric types used.

Cumulative aggregation

Cumulative aggregation computes the total value.

The following example shows you how to aggregate data for a data type:

suspend fun aggregateDistance(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    try {
        val response = healthConnectClient.aggregate(
            AggregateRequest(
                metrics = setOf(DistanceRecord.DISTANCE_TOTAL),
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
            )
        )
        // The result may be null if no data is available in the time range.
        val distanceTotalInMeters = response[DistanceRecord.DISTANCE_TOTAL]?.inMeters ?: 0L
    } catch (e: Exception) {
        // Run error handling here.
    }
}

Statistical aggregation

Statistical aggregation computes the minimum, maximum, or average values.

The following example shows how to use statistical aggregation:

suspend fun aggregateHeartRate(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    try {
        val response =
            healthConnectClient.aggregate(
                AggregateRequest(
                    setOf(HeartRateRecord.BPM_MAX, HeartRateRecord.BPM_MIN),
                    timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
                )
            )
        // The result may be null if no data is available in the time range.
        val minimumHeartRate = response[HeartRateRecord.BPM_MIN]
        val maximumHeartRate = response[HeartRateRecord.BPM_MAX]
    } catch (e: Exception) {
        // Run error handling here.
    }
}

Buckets

Health Connect can also let you aggregate data into buckets. The two types of buckets you can use include duration and period.

Once called, they return a list of buckets. Note that the list can be sparse, so a bucket is not included in the list if it doesn't contain any data.

Duration

In this case, aggregated data is split into buckets within a fixed length of time, such as a minute or an hour. To aggregate data into buckets, use aggregateGroupByDuration. It accepts an AggregateGroupByDurationRequest object where you add the metric types, the time range, and the Duration as parameters.

The following shows an example of aggregating steps into minute-long buckets:

suspend fun aggregateStepsIntoMinutes(
    healthConnectClient: HealthConnectClient,
    startTime: LocalDateTime,
    endTime: LocalDateTime
) {
    try {
        val response =
            healthConnectClient.aggregateGroupByDuration(
                AggregateGroupByDurationRequest(
                    metrics = setOf(StepsRecord.COUNT_TOTAL),
                    timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
                    timeRangeSlicer = Duration.ofMinutes(1L)
                )
            )
        for (durationResult in response) {
            // The result may be null if no data is available in the time range.
            val totalSteps = durationResult.result[StepsRecord.COUNT_TOTAL]
        }
    } catch (e: Exception) {
        // Run error handling here.
    }
}

Period

In this case, aggregated data is split into buckets within a date-based amount of time, such as a week or a month. To aggregate data into buckets, use aggregateGroupByPeriod. It accepts an AggregateGroupByPeriodRequest object where you add the metric types, the time range, and the Period as parameters.

The following shows an example of aggregating steps into monthly buckets:

suspend fun aggregateStepsIntoMonths(
    healthConnectClient: HealthConnectClient,
    startTime: LocalDateTime,
    endTime: LocalDateTime
) {
    try {
        val response =
            healthConnectClient.aggregateGroupByPeriod(
                AggregateGroupByPeriodRequest(
                    metrics = setOf(StepsRecord.COUNT_TOTAL),
                    timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
                    timeRangeSlicer = Period.ofMonths(1)
                )
            )
        for (monthlyResult in response) {
            // The result may be null if no data is available in the time range.
            val totalSteps = monthlyResult.result[StepsRecord.COUNT_TOTAL]
        }
    } catch (e: Exception) {
        // Run error handling here.
    }
}