目標是指使用者在 Google Fit 應用程式中自行設定的目標。有助於使用者每天保持活躍。使用者可以在設定檔中調整每天要達成的步數和心肺強化分數。Fit 平台會記錄目標,並追蹤每日活動情況。
透過目標打造更優質的使用者體驗
應用程式可讀取使用者的目標,藉此追蹤個人目標。這有助於打造更吸引人的體驗。首先,請使用
GoalsClient
敬上
讀取使用者的步數和心肺強化分數目標。然後使用
HistoryClient
客戶,就能瞭解他們達成目標的進度。
您可以利用這項資料,協助使用者在 Google Fit 和您的應用程式之間無縫切換,並在兩個應用程式中取得一致的資訊,瞭解使用者達成健身目標的進度。
提供最新資訊和深入分析資料,鼓勵使用者達成每日目標 與遊戲進度有關
讀取目標
下例說明如何建立新的健身客戶,並取得
使用者的心肺強化分數目標,或是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;
}