Method Signature

Future<List<HealthDataPoint>> getHealthAggregateDataFromTypes({
  required List<HealthDataType> types,
  required DateTime startDate,
  required DateTime endDate,
  int activitySegmentDuration = 1,
  bool includeManualEntry = true,
})

Parameters

ParameterTypeRequiredDefaultDescription
typesList<HealthDataType>Yes-Health data types to query
startDateDateTimeYes-Start of time range
endDateDateTimeYes-End of time range
activitySegmentDurationintNo1Activity segment duration in minutes
includeManualEntryboolNotrueInclude manually entered data

Primary Use: Workout Summaries

This method is optimized for workout and activity data:
final workoutSummaries = await health.getHealthAggregateDataFromTypes(
  types: [
    HealthDataType.WORKOUT,
    HealthDataType.TOTAL_CALORIES_BURNED,
    HealthDataType.DISTANCE_WALKING_RUNNING,
  ],
  startDate: DateTime.now().subtract(Duration(days: 7)),
  endDate: DateTime.now(),
  activitySegmentDuration: 1,
  includeManualEntry: true,
);

for (var point in workoutSummaries) {
  if (point.type == HealthDataType.WORKOUT) {
    final workout = point.value as WorkoutHealthValue;
    print('Workout: ${workout.workoutActivityType.name}');
    print('Duration: ${point.dateTo.difference(point.dateFrom)}');
    
    if (workout.totalEnergyBurned != null) {
      print('Calories: ${workout.totalEnergyBurned}');
    }
  }
}

Activity Segment Duration

Controls the granularity of activity data aggregation:
// 1-minute segments (most detailed)
final detailed = await health.getHealthAggregateDataFromTypes(
  types: [HealthDataType.WORKOUT],
  startDate: start,
  endDate: end,
  activitySegmentDuration: 1,
);

// 5-minute segments (balanced)
final balanced = await health.getHealthAggregateDataFromTypes(
  types: [HealthDataType.WORKOUT],
  startDate: start,
  endDate: end,
  activitySegmentDuration: 5,
);

// 15-minute segments (coarse)
final coarse = await health.getHealthAggregateDataFromTypes(
  types: [HealthDataType.WORKOUT],
  startDate: start,
  endDate: end,
  activitySegmentDuration: 15,
);

Filtering Manual Entries

// Exclude manual entries
final autoOnly = await health.getHealthAggregateDataFromTypes(
  types: [HealthDataType.WORKOUT],
  startDate: start,
  endDate: end,
  includeManualEntry: false,
);

// Include manual entries (default)
final all = await health.getHealthAggregateDataFromTypes(
  types: [HealthDataType.WORKOUT],
  startDate: start,
  endDate: end,
  includeManualEntry: true,
);

Multi-Type Queries

Query multiple related metrics:
final activityData = await health.getHealthAggregateDataFromTypes(
  types: [
    HealthDataType.WORKOUT,
    HealthDataType.ACTIVE_ENERGY_BURNED,
    HealthDataType.DISTANCE_WALKING_RUNNING,
    HealthDataType.STEPS,
    HealthDataType.HEART_RATE,
  ],
  startDate: DateTime.now().subtract(Duration(days: 30)),
  endDate: DateTime.now(),
);

// Group by type
final byType = <HealthDataType, List<HealthDataPoint>>{};
for (var point in activityData) {
  byType.putIfAbsent(point.type, () => []).add(point);
}

print('Workouts: ${byType[HealthDataType.WORKOUT]?.length ?? 0}');
print('Energy data points: ${byType[HealthDataType.ACTIVE_ENERGY_BURNED]?.length ?? 0}');

Use Cases

Workout Dashboard

class WorkoutStats {
  final int totalWorkouts;
  final Duration totalDuration;
  final double totalCalories;
  final double totalDistance;
  
  WorkoutStats({
    required this.totalWorkouts,
    required this.totalDuration,
    required this.totalCalories,
    required this.totalDistance,
  });
}

Future<WorkoutStats> getWorkoutStats(DateTime start, DateTime end) async {
  final data = await health.getHealthAggregateDataFromTypes(
    types: [HealthDataType.WORKOUT],
    startDate: start,
    endDate: end,
  );
  
  int workoutCount = 0;
  Duration totalDuration = Duration.zero;
  double totalCalories = 0;
  double totalDistance = 0;
  
  for (var point in data) {
    if (point.type == HealthDataType.WORKOUT) {
      workoutCount++;
      totalDuration += point.dateTo.difference(point.dateFrom);
      
      final workout = point.value as WorkoutHealthValue;
      totalCalories += workout.totalEnergyBurned ?? 0;
      totalDistance += workout.totalDistance ?? 0;
    }
  }
  
  return WorkoutStats(
    totalWorkouts: workoutCount,
    totalDuration: totalDuration,
    totalCalories: totalCalories,
    totalDistance: totalDistance,
  );
}

Activity Type Breakdown

Future<Map<HealthWorkoutActivityType, int>> getWorkoutTypeBreakdown(
  DateTime start,
  DateTime end,
) async {
  final workouts = await health.getHealthAggregateDataFromTypes(
    types: [HealthDataType.WORKOUT],
    startDate: start,
    endDate: end,
  );
  
  final breakdown = <HealthWorkoutActivityType, int>{};
  
  for (var point in workouts) {
    final workout = point.value as WorkoutHealthValue;
    breakdown[workout.workoutActivityType] = 
        (breakdown[workout.workoutActivityType] ?? 0) + 1;
  }
  
  return breakdown;
}

// Usage
final breakdown = await getWorkoutTypeBreakdown(
  DateTime.now().subtract(Duration(days: 30)),
  DateTime.now(),
);

breakdown.forEach((type, count) {
  print('${type.name}: $count workouts');
});

Platform Differences

  • iOS: Returns workout sessions with summary data
  • Android: Returns aggregate workout data from Health Connect
  • Data structure may vary between platforms

See Also