Class AggregateQuery
Describes a bucketed summary read against HealthStore.
AggregateQuery q = new AggregateQuery()
.addType(HealthDataType.STEPS)
.addMetric(AggregateMetric.TOTAL)
.setTimeRange(HealthTimeRange.calendarDays(7, ZoneId.systemDefault()))
.setBucket(HealthInterval.calendarDays(1, ZoneId.systemDefault()));
Overlapping sources are counted twice, on every platform
When a phone and a watch both record steps for the same walk, the store holds two overlapping sets of samples, and a total over them counts the walk twice.
This includes iOS. HealthKit's statistics engine does de-duplicate overlapping sources -- but no port uses it in this release. Every metric here is computed by shared code from raw samples read back through an ordinary query, so that the bucket arithmetic has one implementation rather than one per platform that can drift. iOS therefore double-counts exactly as Android does. A port that grows a native aggregate path would change that, and this note with it.
This API does not paper over the overlap with a heuristic
de-duplicator -- guessing which of two overlapping sources is
authoritative is exactly the kind of silent wrongness health data
cannot afford. Use addSource(String) to pin the query to the source
you trust, and tell the user which device a figure came from.
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionaddMetric(AggregateMetric metric) Adds a metric to compute.addType(HealthDataType type) Adds a type to summarize.The bucket width, or null for one bucket over the whole range.The metrics this query computes.The source filter, empty when unrestricted.The span this query summarizes.getTypes()The types this query summarizes.getUnit()The requested unit, or null for canonical units.booleanWhether this query asked for source de-duplication.static booleanisMeaningful(HealthDataType type, AggregateMetric metric) Whethermetricsays anything true abouttype.setBucket(HealthInterval bucket) Splits the range into buckets of this width.setDeduplicateSources(boolean deduplicate) Restricts the summary to one writing app -- see the double-counting warning on this class.setTimeRange(HealthTimeRange timeRange) The span to summarize.setUnit(HealthUnit unit) Returns aggregated values inunitrather than each type's canonical unit.voidvalidate()Validates the query and throws if it cannot be run.
-
Constructor Details
-
AggregateQuery
public AggregateQuery()
-
-
Method Details
-
addType
Adds a type to summarize. At least one is required. -
getTypes
The types this query summarizes. -
addMetric
Adds a metric to compute. At least one is required. -
getMetrics
The metrics this query computes. -
setDeduplicateSources
Restricts the summary to one writing app -- see the double-counting warning on this class. Asks the platform to de-duplicate overlapping sources.
Off by default, because the shared rollup cannot do it and most stores therefore cannot honour it. Check
HealthStore.isSourceDeduplicationSupported()first: asking a store that cannot fails the aggregate withHealthError.NOT_SUPPORTEDrather than silently returning the double-counted answer.Where it is honoured -- HealthKit, whose statistics engine does this natively -- a walk recorded by both a phone and a watch is counted once instead of twice.
-
isDeduplicateSources
public boolean isDeduplicateSources()Whether this query asked for source de-duplication. -
addSource
-
getSources
-
setTimeRange
The span to summarize. Required. -
getTimeRange
The span this query summarizes. -
setBucket
Splits the range into buckets of this width. Leave unset for a single bucket covering the whole range.
Prefer
HealthInterval.calendarDays(int,java.time.ZoneId)over a fixed 24-hour width whenever the buckets are labelled with dates in your UI -- seeHealthInterval. -
getBucket
The bucket width, or null for one bucket over the whole range. -
setUnit
Returns aggregated values inunitrather than each type's canonical unit. -
getUnit
The requested unit, or null for canonical units. -
validate
Validates the query and throws if it cannot be run.
Throws
HealthException:HealthError.INVALID_ARGUMENTfor a missing type, metric or range, or for a metric that is meaningless for the requested type;HealthError.UNIT_MISMATCHfor an incompatible unit.
- Throws:
HealthException
-
isMeaningful
Whether
metricsays anything true abouttype.AggregateMetric.COUNTandAggregateMetric.DURATIONapply to everything. Summing a discrete series -- the total of every body mass ever recorded -- and averaging a cumulative one -- the mean of arbitrarily-chunked step totals -- are both meaningless, so they are rejected rather than answered.
-