设定健身目标

目标是指 Google 健身中的目标 应用 用户可自行设置的键值对它们有助于激励用户 。用户可以在个人资料中调整每天希望达到的步数和心肺强化分数目标。Google 健身平台可以记录他们的目标,并跟踪每日目标 针对这些内容进行的活动。

利用目标打造更好的用户体验

您的应用可以读取用户的目标,以跟踪其个人目标。这有助于打造更具吸引力的体验。首先,请使用 GoalsClient 客户端读取用户的步数和心肺强化分数目标。然后使用 HistoryClient 客户需要了解他们离这些目标还有多远。

使用这些数据帮助用户在 Google 健身和您的应用之间切换 并在这两个应用中获得一致的进度信息 实现其健身目标。

通过向用户提供与其进度相关的最新动态和数据分析,激励用户达成每日目标。

读取目标

以下示例展示了如何创建新的 Fitness 客户端并获取用户的心脏积分目标值,如果用户未设置目标值,则返回 null

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"
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 可查看进度。以下示例展示了如何查看用户拥有的心脏积分数。

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")
   
}
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");
           
}
       
});

以百分比计算进度

如果您将总数除以检查进度示例 阅读目标示例中的目标,您就可以计算 以百分比表示目标的完成进度

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)
}
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;
}