Thực hiện các mục tiêu về thể chất

Mục tiêu là các đích trong ứng dụng Google Fit mà người dùng có thể tự đặt cho mình. Chúng giúp thúc đẩy người dùng duy trì hoạt động mỗi ngày. Trong hồ sơ, người dùng có thể điều chỉnh số Bước và Điểm nhịp tim mà họ muốn nhắm đến mỗi ngày. Nền tảng Fit ghi lại mục tiêu và theo dõi hoạt động hằng ngày của trẻ dựa trên các mục tiêu đó.

Tạo trải nghiệm người dùng tốt hơn bằng mục tiêu

Ứng dụng của bạn có thể đọc mục tiêu của người dùng để theo dõi các mục tiêu cá nhân của họ. Điều này có thể giúp tạo ra trải nghiệm hấp dẫn hơn. Để bắt đầu, hãy dùng ứng dụng GoalsClient để đọc các mục tiêu về Số bước và Điểm nhịp tim của một người dùng. Sau đó, hãy dùng ứng dụng HistoryClient để kiểm tra xem họ có đạt được các mục tiêu đó hay không.

Hãy sử dụng dữ liệu này để giúp người dùng chuyển đổi giữa Google Fit và ứng dụng của bạn một cách liền mạch, đồng thời nhận thông tin nhất quán trên cả hai ứng dụng về tiến trình đạt được các mục tiêu thể dục của họ.

Thúc đẩy người dùng đạt được mục tiêu hằng ngày bằng cách cung cấp cho họ thông tin cập nhật và thông tin chi tiết liên quan đến tiến trình của họ.

Đọc mục tiêu

Ví dụ sau đây cho biết cách tạo một ứng dụng Thể dục mới và lấy mục tiêu Điểm nhịp tim của người dùng hoặc null nếu họ chưa đặt mục tiêu.

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

Kiểm tra tiến trình

Sau khi có mục tiêu về Điểm nhịp tim của người dùng, bạn có thể sử dụng HistoryClient để kiểm tra tiến trình của họ. Ví dụ sau đây cho biết cách kiểm tra xem người dùng có bao nhiêu Điểm nhịp tim.

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

Tính tiến trình dưới dạng phần trăm

Nếu chia tổng số từ ví dụ về tiến trình kiểm tra cho mục tiêu trong ví dụ về tính năng đọc mục tiêu, thì bạn có thể tính tiến trình đạt mục tiêu dưới dạng phần trăm.

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