设定健身目标
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
目标是指 Google 健身中的目标
应用
用户可自行设置的键值对它们有助于激励用户
。用户可以在个人资料中调整步数和
他们希望达到的心肺强化分数
。Google 健身平台可以记录他们的目标,并跟踪每日目标
针对这些内容进行的活动。
利用目标打造更好的用户体验
您的应用可以读取用户的目标,以跟踪其个人目标。这个
有助于打造更具吸引力的体验。首先,请使用
GoalsClient
客户端读取用户的步数和心肺强化分数目标。然后使用
HistoryClient
客户需要了解他们离这些目标还有多远。
使用这些数据帮助用户在 Google 健身和您的应用之间切换
并在这两个应用中获得一致的进度信息
实现其健身目标。
向用户提供更新和数据分析,激励他们实现每日目标
与他们的进步息息相关
读取目标
以下示例展示了如何创建新的 Fitness 客户端并获取
用户的心肺强化分数目标,或 null
(如果他们未设置目标)。
Kotlin
private val fitnessOptions: FitnessOptions by lazy {
FitnessOptions.builder()
.addDataType(DataType.TYPE_HEART_POINTS, FitnessOptions.ACCESS_READ)
.build()
}
private val goalsReadRequest: GoalsReadRequest by lazy {
GoalsReadRequest.Builder()
.addDataType(DataType.TYPE_HEART_POINTS)
.build()
}
private fun getGoogleAccount(): GoogleSignInAccount =
GoogleSignIn.getAccountForExtension(requireContext(), fitnessOptions)
private fun readGoals() {
Fitness.getGoalsClient(requireContext(), getGoogleAccount())
.readCurrentGoals(goalsReadRequest)
.addOnSuccessListener { goals ->
// There should be at most one heart points goal currently.
goals.firstOrNull()?.apply {
// What is the value of the goal
val goalValue = metricObjective.value
Log.i(TAG, "Goal value: $goalValue")
// How is the goal measured?
Log.i(TAG, "Objective: $objective")
// How often does the goal repeat?
Log.i(TAG, "Recurrence: $recurrenceDetails")
}
}
}
private val Goal.objective: String
get() = when (objectiveType) {
OBJECTIVE_TYPE_DURATION ->
"Duration (s): ${durationObjective.getDuration(TimeUnit.SECONDS)}"
OBJECTIVE_TYPE_FREQUENCY ->
"Frequency : ${frequencyObjective.frequency}"
OBJECTIVE_TYPE_METRIC ->
"Metric : ${metricObjective.dataTypeName} - ${metricObjective.value}"
else -> "Unknown objective"
}
private val Goal.recurrenceDetails: String
get() = recurrence?.let {
val period = when (it.unit) {
Recurrence.UNIT_DAY -> "days"
Recurrence.UNIT_WEEK -> "weeks"
Recurrence.UNIT_MONTH -> "months"
else -> "Unknown"
}
"Every ${recurrence!!.count} $period"
} ?: "Does not repeat"
Java
private final FitnessOptions fitnessOptions = FitnessOptions.builder()
.addDataType(DataType.TYPE_HEART_POINTS, FitnessOptions.ACCESS_READ)
.build();
private final GoalsReadRequest goalsReadRequest = new GoalsReadRequest.Builder()
.addDataType(DataType.TYPE_HEART_POINTS)
.build();
private GoogleSignInAccount getGoogleAccount() {
GoogleSignIn.getAccountForExtension(getApplicationContext(), fitnessOptions);
}
private void readGoals() {
Fitness.getGoalsClient(getApplicationContext(), getGoogleAccount())
.readCurrentGoals(goalsReadRequest)
.addOnSuccessListener(goals -> {
// There should be at most one heart points goal currently.
Optional<Goal> optionalGoal = goals.stream().findFirst();
if (optionalGoal.isPresent()) {
// What is the value of the goal
double goalValue = optionalGoal.get().getMetricObjective().getValue();
Log.i(TAG, "Goal value: $goalValue");
// How is the goal measured?
Log.i(TAG, "Objective: ${getObjective(optionalGoal.get())}");
// How often does the goal repeat?
Log.i(TAG, "Recurrence: ${getRecurrenceDetails(optionalGoal.get())}");
}
});
}
private String getObjective(Goal goal) {
switch (goal.getObjectiveType()) {
case OBJECTIVE_TYPE_DURATION:
return "Duration (s): ${goal.getDurationObjective().getDuration(TimeUnit.SECONDS)}";
case OBJECTIVE_TYPE_FREQUENCY:
return "Frequency : ${goal.getFrequencyObjective().getFrequency()}";
case OBJECTIVE_TYPE_METRIC:
return "Metric : ${goal.getMetricObjective().getDataTypeName()} - ${goal.getMetricObjective().getValue()}";
default:
return "Unknown objective";
}
}
private String getRecurrenceDetails(Goal goal) {
Goal.Recurrence recurrence = goal.getRecurrence();
if (recurrence == null) {
return "Does not repeat";
}
StringBuilder recurrenceMessage = new StringBuilder("Every ${recurrence.getCount()}");
switch (recurrence.getUnit()) {
case UNIT_DAY:
recurrenceMessage.append("days");
break;
case UNIT_WEEK:
recurrenceMessage.append("weeks");
break;
case UNIT_MONTH:
recurrenceMessage.append("months");
break;
default:
recurrenceMessage.delete(0, recurrenceMessage.length());
recurrenceMessage.append("Unknown");
break;
}
return recurrenceMessage.toString();
}
查看进度
在达成用户的心肺强化分数目标后,您可以使用
HistoryClient
可查看进度。以下
示例展示了如何查看用户的心肺强化分数。
Kotlin
val current = Calendar.getInstance()
val request = DataReadRequest.Builder()
.read(DataType.TYPE_HEART_POINTS)
.setTimeRange(
goal.getStartTime(current, TimeUnit.NANOSECONDS),
goal.getEndTime(current, TimeUnit.NANOSECONDS),
TimeUnit.NANOSECONDS
)
.build()
Fitness.getHistoryClient(requireContext(), getGoogleAccount())
.readData(request)
.addOnSuccessListener { response ->
val heartPointsSet = response.dataSets.first()
val totalHeartPoints = heartPointsSet.dataPoints.sumBy {
it.getValue(Field.FIELD_INTENSITY).asFloat().toInt()
}
Log.i(TAG, "Total heart points: $totalHeartPoints")
}
Java
Calendar current = Calendar.getInstance();
DataReadRequest request = new DataReadRequest.Builder()
.read(DataType.TYPE_HEART_POINTS)
.setTimeRange(
goal.getStartTime(current, TimeUnit.NANOSECONDS),
goal.getEndTime(current, TimeUnit.NANOSECONDS),
TimeUnit.NANOSECONDS
)
.build();
Fitness.getHistoryClient(getApplicationContext(), getGoogleAccount())
.readData(request)
.addOnSuccessListener(response -> {
Optional<DataSet> heartPointsSet = response.getDataSets().stream().findFirst();
if (heartPointsSet.isPresent()) {
int totalHeartPoints = 0;
for (DataPoint dp : heartPointsSet.get().getDataPoints()) {
totalHeartPoints += (int) dp.getValue(Field.FIELD_INTENSITY).asFloat();
}
Log.i(TAG, "Total heart points: $totalHeartPoints");
}
});
以百分比计算进度
如果您将总数除以检查进度示例
阅读目标示例中的目标,您可以计算
以百分比表示目标的完成进度
Kotlin
private fun calculateProgressPercentage(goal: Goal, response: DataReadResponse): Double {
val goalValue = goal.metricObjective.value
val currentTotal = response.dataSets.first().dataPoints.sumBy {
it.getValue(Field.FIELD_INTENSITY).asFloat().toInt()
}
return (currentTotal.div(goalValue)).times(100.0)
}
Java
private double calculateProgressPercentage(Goal goal, DataReadResponse response) {
double goalValue = goal.getMetricObjective().getValue();
Optional<DataSet> firstDataSet = response.getDataSets().stream().findFirst();
if (!(firstDataSet.isPresent())) {
return NaN;
}
double currentTotal = 0;
for (DataPoint dp : firstDataSet.get().getDataPoints()) {
currentTotal += (int)dp.getValue(Field.FIELD_INTENSITY).asFloat();
}
return (currentTotal / goalValue) * 100.0;
}
如未另行说明,那么本页面中的内容已根据知识共享署名 4.0 许可获得了许可,并且代码示例已根据 Apache 2.0 许可获得了许可。有关详情,请参阅 Google 开发者网站政策。Java 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-08-31。
[null,null,["最后更新时间 (UTC):2025-08-31。"],[[["\u003cp\u003eGoogle Fit goals, encompassing Steps and Heart Points, motivate users to maintain daily activity.\u003c/p\u003e\n"],["\u003cp\u003eYour app can utilize the \u003ccode\u003eGoalsClient\u003c/code\u003e and \u003ccode\u003eHistoryClient\u003c/code\u003e to access user goals and activity history, fostering a more personalized user experience.\u003c/p\u003e\n"],["\u003cp\u003eBy integrating with Google Fit goals, your app can seamlessly provide users with consistent progress updates and encourage them to achieve their fitness objectives.\u003c/p\u003e\n"],["\u003cp\u003eCode examples in Kotlin and Java demonstrate how to read user goals, track progress, and calculate the percentage of goal completion.\u003c/p\u003e\n"]]],[],null,["# Work with fitness goals\n\nGoals are targets in the [Google Fit\napp](https://play.google.com/store/apps/details?id=com.google.android.apps.fitness)\nthat users can set for themselves. They help motivate users to stay active every\nday. From within their profile, users can adjust how many Steps and\n[Heart Points](https://support.google.com/fit/answer/7619539) they want to aim\nfor each day. The Fit platform records their goals and tracks their daily\nactivity against these.\n\nCreate a better user experience with goals\n------------------------------------------\n\nYour app can read a user's goals to keep track of their personal targets. This\ncan help create a more engaging experience. To start, use the\n[`GoalsClient`](/android/reference/com/google/android/gms/fitness/GoalsClient)\nclient to read a user's Steps and Heart Points goals. Then use the\n[`HistoryClient`](/android/reference/com/google/android/gms/fitness/HistoryClient)\nclient to check how close they are to those goals.\n\nUse this data to help users switch between Google Fit and your app\nseamlessly, and get consistent information across both apps about their progress\ntowards their fitness goals.\n\nMotivate users to reach their daily goals by giving them updates and insights\nrelated to their progress.\n\nRead a goal\n-----------\n\nThe following example shows how to create a new Fitness client and get the\nuser's Heart Points goal, or `null` if they don't have a goal set. \n\n### Kotlin\n\n```kotlin\nprivate val fitnessOptions: FitnessOptions by lazy {\n FitnessOptions.builder()\n .addDataType(DataType.TYPE_HEART_POINTS, FitnessOptions.ACCESS_READ)\n .build()\n}\n\nprivate val goalsReadRequest: GoalsReadRequest by lazy {\n GoalsReadRequest.Builder()\n .addDataType(DataType.TYPE_HEART_POINTS)\n .build()\n}\n\nprivate fun getGoogleAccount(): GoogleSignInAccount =\n GoogleSignIn.getAccountForExtension(requireContext(), fitnessOptions)\n\n\nprivate fun readGoals() {\n Fitness.getGoalsClient(requireContext(), getGoogleAccount())\n .readCurrentGoals(goalsReadRequest)\n .addOnSuccessListener { goals -\u003e\n // There should be at most one heart points goal currently.\n goals.firstOrNull()?.apply {\n // What is the value of the goal\n val goalValue = metricObjective.value\n Log.i(TAG, \"Goal value: $goalValue\")\n\n // How is the goal measured?\n Log.i(TAG, \"Objective: $objective\")\n\n // How often does the goal repeat?\n Log.i(TAG, \"Recurrence: $recurrenceDetails\")\n }\n }\n}\n\nprivate val Goal.objective: String\n get() = when (objectiveType) {\n OBJECTIVE_TYPE_DURATION -\u003e\n \"Duration (s): ${durationObjective.getDuration(TimeUnit.SECONDS)}\"\n OBJECTIVE_TYPE_FREQUENCY -\u003e\n \"Frequency : ${frequencyObjective.frequency}\"\n OBJECTIVE_TYPE_METRIC -\u003e\n \"Metric : ${metricObjective.dataTypeName} - ${metricObjective.value}\"\n else -\u003e \"Unknown objective\"\n }\n\nprivate val Goal.recurrenceDetails: String\n get() = recurrence?.let {\n val period = when (it.unit) {\n Recurrence.UNIT_DAY -\u003e \"days\"\n Recurrence.UNIT_WEEK -\u003e \"weeks\"\n Recurrence.UNIT_MONTH -\u003e \"months\"\n else -\u003e \"Unknown\"\n }\n \"Every ${recurrence!!.count} $period\"\n } ?: \"Does not repeat\"\n```\n\n### Java\n\n```java\nprivate final FitnessOptions fitnessOptions = FitnessOptions.builder()\n .addDataType(DataType.TYPE_HEART_POINTS, FitnessOptions.ACCESS_READ)\n .build();\n\n\nprivate final GoalsReadRequest goalsReadRequest = new GoalsReadRequest.Builder()\n .addDataType(DataType.TYPE_HEART_POINTS)\n .build();\n\nprivate GoogleSignInAccount getGoogleAccount() {\n GoogleSignIn.getAccountForExtension(getApplicationContext(), fitnessOptions);\n}\n\n\nprivate void readGoals() {\n Fitness.getGoalsClient(getApplicationContext(), getGoogleAccount())\n .readCurrentGoals(goalsReadRequest)\n .addOnSuccessListener(goals -\u003e {\n // There should be at most one heart points goal currently.\n Optional\u003cGoal\u003e optionalGoal = goals.stream().findFirst();\n if (optionalGoal.isPresent()) {\n // What is the value of the goal\n double goalValue = optionalGoal.get().getMetricObjective().getValue();\n Log.i(TAG, \"Goal value: $goalValue\");\n\n // How is the goal measured?\n Log.i(TAG, \"Objective: ${getObjective(optionalGoal.get())}\");\n\n // How often does the goal repeat?\n Log.i(TAG, \"Recurrence: ${getRecurrenceDetails(optionalGoal.get())}\");\n }\n\n });\n}\n\nprivate String getObjective(Goal goal) {\n switch (goal.getObjectiveType()) {\n case OBJECTIVE_TYPE_DURATION:\n return \"Duration (s): ${goal.getDurationObjective().getDuration(TimeUnit.SECONDS)}\";\n case OBJECTIVE_TYPE_FREQUENCY:\n return \"Frequency : ${goal.getFrequencyObjective().getFrequency()}\";\n case OBJECTIVE_TYPE_METRIC:\n return \"Metric : ${goal.getMetricObjective().getDataTypeName()} - ${goal.getMetricObjective().getValue()}\";\n default:\n return \"Unknown objective\";\n }\n}\n\nprivate String getRecurrenceDetails(Goal goal) {\n Goal.Recurrence recurrence = goal.getRecurrence();\n if (recurrence == null) {\n return \"Does not repeat\";\n }\n\n StringBuilder recurrenceMessage = new StringBuilder(\"Every ${recurrence.getCount()}\");\n\n switch (recurrence.getUnit()) {\n case UNIT_DAY:\n recurrenceMessage.append(\"days\");\n break;\n case UNIT_WEEK:\n recurrenceMessage.append(\"weeks\");\n break;\n case UNIT_MONTH:\n recurrenceMessage.append(\"months\");\n break;\n default:\n recurrenceMessage.delete(0, recurrenceMessage.length());\n recurrenceMessage.append(\"Unknown\");\n break;\n }\n\n return recurrenceMessage.toString();\n}\n```\n\nCheck progress\n--------------\n\nAfter you have the user's Heart Points goal, you can use the\n[`HistoryClient`](/fit/android/history) to check their progress. The following\nexample shows how to check how many Heart Points the user has.\n**Note:** The time range for a goal is calculated based on its frequency. For example, for a daily goal, the current time is used to calculate when the day starts and ends. Where the goal is a daily goal, the code can be simplified by using [`HistoryClient.readDailyTotal()`](/android/reference/com/google/android/gms/fitness/HistoryClient#public-taskdataset-readdailytotal-datatype-datatype) instead of [`HistoryClient.readData()`](/android/reference/com/google/android/gms/fitness/HistoryClient#public-taskdatareadresponse-readdata-datareadrequest-request). This example only uses `HistoryClient.readData()` to show how Goal objects can be used to identify the start and end times of the current recurrence when you query for progress. \n\n### Kotlin\n\n```kotlin\nval current = Calendar.getInstance()\nval request = DataReadRequest.Builder()\n .read(DataType.TYPE_HEART_POINTS)\n .setTimeRange(\n goal.getStartTime(current, TimeUnit.NANOSECONDS),\n goal.getEndTime(current, TimeUnit.NANOSECONDS),\n TimeUnit.NANOSECONDS\n )\n .build()\n\nFitness.getHistoryClient(requireContext(), getGoogleAccount())\n .readData(request)\n .addOnSuccessListener { response -\u003e\n val heartPointsSet = response.dataSets.first()\n val totalHeartPoints = heartPointsSet.dataPoints.sumBy {\n it.getValue(Field.FIELD_INTENSITY).asFloat().toInt()\n }\n Log.i(TAG, \"Total heart points: $totalHeartPoints\")\n }\n```\n\n### Java\n\n```java\nCalendar current = Calendar.getInstance();\nDataReadRequest request = new DataReadRequest.Builder()\n .read(DataType.TYPE_HEART_POINTS)\n .setTimeRange(\n goal.getStartTime(current, TimeUnit.NANOSECONDS),\n goal.getEndTime(current, TimeUnit.NANOSECONDS),\n TimeUnit.NANOSECONDS\n )\n .build();\n\n\nFitness.getHistoryClient(getApplicationContext(), getGoogleAccount())\n .readData(request)\n .addOnSuccessListener(response -\u003e {\n Optional\u003cDataSet\u003e heartPointsSet = response.getDataSets().stream().findFirst();\n if (heartPointsSet.isPresent()) {\n int totalHeartPoints = 0;\n for (DataPoint dp : heartPointsSet.get().getDataPoints()) {\n totalHeartPoints += (int) dp.getValue(Field.FIELD_INTENSITY).asFloat();\n }\n\n Log.i(TAG, \"Total heart points: $totalHeartPoints\");\n }\n });\n```\n\nCalculate progress as a percentage\n----------------------------------\n\nIf you divide the total from the [check progress](#check-progress) example\nby the target in the [read a goal](#read-a-goal) example, you can calculate the\nprogress towards the goal as a percentage. \n\n### Kotlin\n\n```kotlin\nprivate fun calculateProgressPercentage(goal: Goal, response: DataReadResponse): Double {\n val goalValue = goal.metricObjective.value\n val currentTotal = response.dataSets.first().dataPoints.sumBy {\n it.getValue(Field.FIELD_INTENSITY).asFloat().toInt()\n }\n\n return (currentTotal.div(goalValue)).times(100.0)\n}\n```\n\n### Java\n\n```java\nprivate double calculateProgressPercentage(Goal goal, DataReadResponse response) {\n double goalValue = goal.getMetricObjective().getValue();\n Optional\u003cDataSet\u003e firstDataSet = response.getDataSets().stream().findFirst();\n if (!(firstDataSet.isPresent())) {\n return NaN;\n }\n double currentTotal = 0;\n for (DataPoint dp : firstDataSet.get().getDataPoints()) {\n currentTotal += (int)dp.getValue(Field.FIELD_INTENSITY).asFloat();\n }\n\n return (currentTotal / goalValue) * 100.0;\n}\n```"]]