hkworkout totalenergyburned 与 HKQuantityTypeIdentifierActiveEnergyBurned 不相关

hkworkout totalenergyburned doesn't correlate with HKQuantityTypeIdentifierActiveEnergyBurned

这更像是一个数据结构问题,而不是编程语法问题。 Health app的数据结构有点像黑盒子。

我想查询 HKHealthStore 并创建包括 ActiveEnergyBurned 在内的项目的每日摘要,以及包括 totalEnergyBurned 在内的锻炼摘要。

我有成功检索此信息的代码(如下)。然而,每天的总数通常比当天的锻炼少!我确信我的代码没有问题,因为 Apple Health 应用程序中显示的数字完全相同。例如:

昨天的锻炼: 我的应用 workout.totalEnergyBurned = 905 大卡 昨天 ActiveEnergyBurned 的总和 655 kcal 健康应用显示两者的数字完全相同。

如果 ActiveEnergyBurned 不包括锻炼,它包括什么?我没有另外 655 的 ActiveEnergyBurned。在我看来,ActiveEnergyBurned 不可能不包括锻炼!

   //to get sum of day's activeCaloriesBurned:

func getActiveCalories(startDate:NSDate, endDate:NSDate){
    let sampleType =      HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierActiveEnergyBurned)
    let hkUnit = HKUnit.kilocalorieUnit()

    getSumStatsFor(sampleType, hkUnit: hkUnit, startDate: startDate, endDate: endDate) { (hdObject, result) -> Void in
        hdObject.activeCalories = result
    }
}

func getTotalsForDataType(quantitiyType:HKQuantityType, startDate:NSDate,      endDate:NSDate, completion:(HKStatisticsCollection!, NSError!) -> Void){
    println("getTotalsForDataType start: \(startDate) end: \(endDate)")
    let dayStart = NSCalendar.currentCalendar().startOfDayForDate(startDate)
    let addDay = NSCalendar.currentCalendar().dateByAddingUnit(.CalendarUnitDay, value: 1, toDate: endDate, options:nil)
    let dayEnd = NSCalendar.currentCalendar().startOfDayForDate(addDay!)  //add one day
    let interval = NSDateComponents()
    interval.day = 1

    let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: endDate, options: HKQueryOptions.None)
    let newQuery = HKStatisticsCollectionQuery(quantityType: quantitiyType,
                                    quantitySamplePredicate: predicate,
                                                    options: HKStatisticsOptions.CumulativeSum,
                                                 anchorDate: dayStart,
                                         intervalComponents: interval)
    newQuery.initialResultsHandler = {
        query, results, error in
        if error != nil {
            println("*** An error occurred while calculating the statistics: \(error.localizedDescription) ***")
            completion(nil, error)
        }else{
            completion(results,error)
        }
    }
  self.healthKitStore.executeQuery(newQuery)
}

//to get workout totalCalories burned

func readWorkouts(completion: (([AnyObject]!, NSError!) ->Void)!){
        let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
    let sampleQuery = HKSampleQuery(sampleType: HKWorkoutType.workoutType(), predicate: nil, limit: 0, sortDescriptors: [sortDescriptor]) { (sampleQuery, results, error) -> Void in
            if let queryError = error {
            println( "There was an error while reading the samples: \(queryError.localizedDescription)")
        }
        completion(results,error)
    }
    healthKitStore.executeQuery(sampleQuery)
}

这是由于 HealthKit 锻炼 API 的设计方式存在错误。使用当前的 API,第 3 方应用程序可以创建 HKWorkout,其中 totalEnergyBurned 大于 0,但 HKQuantityTypeIdentifierActiveEnergyBurned 类型的关联 HKSamples 是创建总计 totalEnergyBurned。例如,将锻炼数据输入 HealthKit 的第 3 方应用程序可以这样做:

HKHealthStore *healthStore = [HKHealthStore new];
HKWorkout *workout = [HKWorkout workoutWithActivityType:HKWorkoutActivityTypePlay
                                               startDate:[NSDate date]
                                                 endDate:[NSDate date]
                                                duration:100.0
                                       totalEnergyBurned:[HKQuantity quantityWithUnit:[HKUnit kilocalorieUnit] doubleValue:445]
                                           totalDistance:[HKQuantity quantityWithUnit:[HKUnit meterUnit] doubleValue:1000]
                                                metadata:nil];
[healthStore saveObject:workout withCompletion:nil];

请注意,没有任何地方 HKSamples 创建类型 HKQuantityTypeIdentifierActiveEnergyBurned。然后,当您总结当天消耗的活性能量并将其与锻炼消耗的总能量进行比较时,您将得到 0 kcal 与 445 kcal。一个好的第 3 方应用程序在创建锻炼后会做的是:

NSArray *workoutSamples = @[[HKQuantitySample quantitySampleWithType:HKQuantityTypeIdentifierActiveEnergyBurned
                                                            quantity:[HKQuantity quantityWithUnit:[HKUnit kilocalorieUnit] doubleValue:workout.totalEnergyBurned]
                                                           startDate:workout.startDate
                                                             endDate:workout.endDate]];
[healthStore addSamples:workoutSamples toWorkout:workout completion:nil];

这样至少只有活性能量燃烧样本。现在你会得到 445 kcal vs 445 kcal。

在我对第 3 方应用程序的测试中,我发现大多数应用程序都添加了活性能量燃烧样本,但有些应用程序,如 Nike 运行,则没有。

一个 hacky 的解决方法是提取所有的活动能量样本进行锻炼(你必须使用 startDateendDate 因为 predicateForObjectsFromWorkout 有类似的问题如上所述),那么如果没有任何样本,则假设源没有为该锻炼创建活性能量样本并将锻炼的 totalEnergyBurned 添加到当天的活性能量消耗总和中。