使用时段

“时段”表示用户进行健身活动的时间间隔。Sessions API 可让您的应用在健身存储区中创建会话。

对于持续的健身活动(用户在开始和结束健身活动时会通知您的应用),您可以实时创建时段。

您还可以在健身活动结束后或者从 Google 健身外部导入数据和健身课程时,将锻炼活动插入健身商店。

实时创建会话

如需为持续性健身活动创建时段,请完成以下步骤:

  1. 使用 RecordingClient.subscribe 方法订阅健身数据

  2. 在用户发起健身活动时,使用 SessionsClient.startSession 方法启动会话

  3. 在用户结束健身活动后,使用 SessionsClient.stopSession 方法停止会话

  4. 使用 RecordingClient.unsubscribe 方法退订健身数据,您不再对此数据不感兴趣。

启动会话

如需在应用中启动会话,请使用 SessionsClient.startSession 方法:

Kotlin

// 1. Subscribe to fitness data
// 2. Create a session object
// (provide a name, identifier, description, activity and start time)
val session = Session.Builder()
    .setName(sessionName)
    .setIdentifier("UniqueIdentifierHere")
    .setDescription("Morning run")
    .setActivity(FitnessActivities.RUNNING)
    .setStartTime(startTime, TimeUnit.MILLISECONDS)
    .build()

// 3. Use the Sessions client to start a session:
Fitness.getSessionsClient(this, googleSigninAccount)
    .startSession(session)
    .addOnSuccessListener {
        Log.i(TAG, "Session started successfully!")
    }
    .addOnFailureListener { e ->
        Log.w(TAG, "There was an error starting the session", e)
    }

Java

// 1. Subscribe to fitness data
// 2. Create a session object
// (provide a name, identifier, description, activity and start time)
Session session = new Session.Builder()
        .setName(sessionName)
        .setIdentifier("UniqueIdentifierHere")
        .setDescription("Morning run")
        .setActivity(FitnessActivities.RUNNING)
        .setStartTime(startTime, TimeUnit.MILLISECONDS)
        .build();

// 3. Use the Sessions client to start a session:
Fitness.getSessionsClient(this, googleSigninAccount)
        .startSession(session)
        .addOnSuccessListener(unused ->
                Log.i(TAG, "Session started successfully!"))
        .addOnFailureListener(e ->
                Log.w(TAG, "There was an error starting the session", e));

停止会话

如需在您的应用中停止会话,请使用 SessionsClient.stopSession 方法:

Kotlin

// Invoke the SessionsClient with the session identifier
Fitness.getSessionsClient(this, googleSigninAccount)
    .stopSession(session.getIdentifier())
    .addOnSuccessListener {
        Log.i(TAG, "Session stopped successfully!")

        // Now unsubscribe from the fitness data (see
        // Recording Fitness data)
    }
    .addOnFailureListener { e ->
        Log.w(TAG, "There was an error stopping the session", e)
    }

Java

// Invoke the SessionsClient with the session identifier
Fitness.getSessionsClient(this, googleSigninAccount)
        .stopSession(session.getIdentifier())
        .addOnSuccessListener (unused -> {
            Log.i(TAG, "Session stopped successfully!");
            // Now unsubscribe from the fitness data (see
            // Recording Fitness data)
        })
        .addOnFailureListener(e ->
                Log.w(TAG, "There was an error stopping the session", e));

生成的会话包含以下参数:

  • 开始时间:应用调用 SessionsClient.startSession 方法的时间。

  • 结束时间:您的应用调用 SessionsClient.stopSession 方法的时间。

  • 名称:您传递给 SessionsClient.startSessionSession 对象中的名称。

在健身商店中插入课程

若要插入包含您之前收集的数据的会话,请执行以下操作:

  1. 创建一个 Session 对象,用于指定时间间隔和其他所需信息。

  2. 为该会话创建 SessionInsertRequest

  3. (可选)添加数据集和聚合数据点。

  4. 使用 SessionsClient.insertSession 方法插入会话。

插入会话

如需将包含会话元数据的健身数据插入到用户的健身记录中,请先创建一个 SessionInsertRequest 实例:

Kotlin

// Create a session with metadata about the activity.
val session = Session.Builder()
    .setName(SAMPLE_SESSION_NAME)
    .setIdentifier("UniqueIdentifierHere")
    .setDescription("Long run around Shoreline Park")

    .setActivity(FitnessActivities.RUNNING)
    .setStartTime(startTime, TimeUnit.MILLISECONDS)
    .setEndTime(endTime, TimeUnit.MILLISECONDS)
    .build()

// Build a session insert request
val insertRequest = SessionInsertRequest.Builder()
    .setSession(session)
    // Optionally add DataSets for this session.
    .addDataSet(dataset)
    .build()

Java

// Create a session with metadata about the activity.
Session session = new Session.Builder()
        .setName(SAMPLE_SESSION_NAME)
        .setIdentifier("UniqueIdentifierHere")
        .setDescription("Long run around Shoreline Park")

        .setActivity(FitnessActivities.RUNNING)
        .setStartTime(startTime, TimeUnit.MILLISECONDS)
        .setEndTime(endTime, TimeUnit.MILLISECONDS)
        .build();

// Build a session insert request
SessionInsertRequest insertRequest = new SessionInsertRequest.Builder()
        .setSession(session)
        // Optionally add DataSets for this session.
        .addDataSet(dataset)
        .build();

SessionInsertRequest 类提供了一些便捷方法,可用于将数据插入健身记录中,并在对 SessionsClient.insertSession 的同一调用中创建时段。插入数据集(如有),就像您先调用了 HistoryClient.insertData 方法一样,然后创建会话。

Kotlin

Fitness.getSessionsClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions))
    .insertSession(insertRequest)
    .addOnSuccessListener {
        Log.i(TAG, "Session insert was successful!")
    }
    .addOnFailureListener { e ->
        Log.w(TAG, "There was a problem inserting the session: ", e)
    }

Java

Fitness.getSessionsClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions))
        .insertSession(insertRequest)
        .addOnSuccessListener (unused ->
                Log.i(TAG, "Session insert was successful!"))
        .addOnFailureListener(e ->
        Log.w(TAG, "There was a problem inserting the session: ", e));

插入活动细分

Google 健身中的活动细分数据会指明用户在给定时间间隔内执行的健身活动。活动片段数据的类型为 com.google.activity.segment (TYPE_ACTIVITY_SEGMENT),对于支持锻炼期间的暂停尤为有用。

例如,如果您使用 Session.Builder.setActivity() 方法创建一个 30 分钟的跑步会话,但用户在中间休息 10 分钟,您的应用会错误地显示用户跑步了 30 分钟。假设您的应用可以检测用户是在步行还是跑步,那么通过活动片段数据,应用就可以指示用户跑步 10 分钟,步行 10 分钟,然后又跑步 10 分钟。其他应用也可以通过查看您插入的活动细分数据来正确报告 activity。

如需向时段添加活动细分数据,请创建一个包含 com.google.activity.segment 类型的点的数据集。其中每个点都表示用户执行单一活动类型的连续时间间隔。

前面的跑步和步行示例需要三个活动细分点:一个用于在开始的 10 分钟内跑步,一个用于在接下来 10 分钟内步行,另一个用于在最后 10 分钟内跑步。

Kotlin

// Create a DataSet of ActivitySegments to indicate the runner walked for
// 10 minutes in the middle of a run.
val activitySegmentDataSource = DataSource.Builder()
    .setAppPackageName(this.packageName)
    .setDataType(DataType.TYPE_ACTIVITY_SEGMENT)
    .setStreamName(SAMPLE_SESSION_NAME + "-activity segments")
    .setType(DataSource.TYPE_RAW)
    .build()

val firstRunningDp = DataPoint.builder(activitySegmentDataSource)
    .setActivityField(Field.FIELD_ACTIVITY, FitnessActivities.RUNNING)
    .setTimeInterval(startTime, startWalkTime, TimeUnit.MILLISECONDS)
    .build()

val walkingDp = DataPoint.builder(activitySegmentDataSource)
    .setActivityField(Field.FIELD_ACTIVITY, FitnessActivities.WALKING)
    .setTimeInterval(startWalkTime, endWalkTime, TimeUnit.MILLISECONDS)
    .build()

val secondRunningDp = DataPoint.builder(activitySegmentDataSource)
    .setActivityField(Field.FIELD_ACTIVITY, FitnessActivities.RUNNING)
    .setTimeInterval(endWalkTime, endTime, TimeUnit.MILLISECONDS)
    .build()

val activitySegments = DataSet.builder(activitySegmentDataSource)
    .addAll(listOf(firstRunningDp, walkingDp, secondRunningDp))
    .build()

// Create a session with metadata about the activity.
val session = Session.Builder()
    .setName(SAMPLE_SESSION_NAME)
    .setDescription("Long run around Shoreline Park")
    .setIdentifier("UniqueIdentifierHere")
    .setActivity(FitnessActivities.RUNNING)
    .setStartTime(startTime, TimeUnit.MILLISECONDS)
    .setEndTime(endTime, TimeUnit.MILLISECONDS)
    .build()

// Build a session insert request
val insertRequest = SessionInsertRequest.Builder()
    .setSession(session)
    .addDataSet(activitySegments)
    .build()

Java

// Create a DataSet of ActivitySegments to indicate the runner walked for
// 10 minutes in the middle of a run.
DataSource activitySegmentDataSource = new DataSource.Builder()
        .setAppPackageName(getPackageName())
        .setDataType(DataType.TYPE_ACTIVITY_SEGMENT)
        .setStreamName(SAMPLE_SESSION_NAME + "-activity segments")
        .setType(DataSource.TYPE_RAW)
        .build();

DataPoint firstRunningDp = DataPoint.builder(activitySegmentDataSource)
        .setActivityField(Field.FIELD_ACTIVITY, FitnessActivities.RUNNING)
        .setTimeInterval(startTime, startWalkTime, TimeUnit.MILLISECONDS)
        .build();

DataPoint walkingDp = DataPoint.builder(activitySegmentDataSource)
        .setActivityField(Field.FIELD_ACTIVITY, FitnessActivities.WALKING)
        .setTimeInterval(startWalkTime, endWalkTime, TimeUnit.MILLISECONDS)
        .build();

DataPoint secondRunningDp = DataPoint.builder(activitySegmentDataSource)
        .setActivityField(Field.FIELD_ACTIVITY, FitnessActivities.RUNNING)
        .setTimeInterval(endWalkTime, endTime, TimeUnit.MILLISECONDS)
        .build();

DataSet activitySegments = DataSet.builder(activitySegmentDataSource)
        .addAll(Arrays.asList(firstRunningDp, walkingDp, secondRunningDp))
        .build();

// Create a session with metadata about the activity.
Session session = new Session.Builder()
        .setName(SAMPLE_SESSION_NAME)
        .setDescription("Long run around Shoreline Park")
        .setIdentifier("UniqueIdentifierHere")
        .setActivity(FitnessActivities.RUNNING)
        .setStartTime(startTime, TimeUnit.MILLISECONDS)
        .setEndTime(endTime, TimeUnit.MILLISECONDS)
        .build();

// Build a session insert request
SessionInsertRequest insertRequest = new SessionInsertRequest.Builder()
        .setSession(session)
        .addDataSet(activitySegments)
        .build();

使用时段读取健身数据

Sessions API 可让您从健身存储区获取符合某些条件的会话列表。例如,您可以获取时间间隔内包含的所有会话,或者按名称或 ID 获取特定会话。您还可以指定您是您的应用还是任何应用创建的会话感兴趣。

如需获取符合某些条件的会话列表,请先创建一个 SessionReadRequest 实例:

Kotlin

// Use a start time of 1 week ago and an end time of now.
val endTime = LocalDateTime.now().atZone(ZoneId.systemDefault())
val startTime = endTime.minusWeeks(1)

// Build a session read request
val readRequest = SessionReadRequest.Builder()
    .setTimeInterval(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS)
    .read(DataType.TYPE_SPEED)
    .setSessionName(SAMPLE_SESSION_NAME)
    .build()

Java

// Use a start time of 1 week ago and an end time of now.
ZonedDateTime endTime = LocalDateTime.now().atZone(ZoneId.systemDefault())
ZonedDateTime startTime = endTime.minusWeeks(1)

// Build a session read request
SessionReadRequest readRequest = new SessionReadRequest.Builder()
        .setTimeInterval(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS)
        .read(DataType.TYPE_SPEED)
        .setSessionName(SAMPLE_SESSION_NAME)
        .build();

然后使用 SessionsClient.readSession 方法:

Kotlin

Fitness.getSessionsClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions))
    .readSession(readRequest)
    .addOnSuccessListener { response ->
        // Get a list of the sessions that match the criteria to check the result.
        val sessions = response.sessions
        Log.i(TAG, "Number of returned sessions is: ${sessions.size}")
        for (session in sessions) {
            // Process the session
            dumpSession(session)

            // Process the data sets for this session
            val dataSets = response.getDataSet(session)
            for (dataSet in dataSets) {
                // ...
            }
        }
    }
    .addOnFailureListener { e ->
        Log.w(TAG,"Failed to read session", e)
    }

Java

Fitness.getSessionsClient(this, GoogleSignIn.getAccountForExtension(this, fitnessOptions))
        .readSession(readRequest)
        .addOnSuccessListener(response -> {
            // Get a list of the sessions that match the criteria to check the
            // result.
            List<Session> sessions = response.getSessions();
            Log.i(TAG, "Number of returned sessions is: ${sessions.size}");
            for (Session session : sessions) {
                // Process the session
                dumpSession(session);

                // Process the data sets for this session
                List<DataSet> dataSets = response.getDataSet(session);
                for (DataSet dataSet : dataSets) {
                    // ...
                }
            }
        })
        .addOnFailureListener(e ->
                Log.w(TAG,"Failed to read session", e));

使用时段读取睡眠数据

睡眠时段被认为与其他活动时段不同。默认情况下,读取响应仅包含活动时段,而不包含睡眠时段。

如需包含睡眠时段,请在构建 SessionReadRequest 时使用 includeSleepSessions 方法。如需同时包含 activity 和会话,请同时使用 includeSleepSessionsincludeActivitySessions

显示其他应用中的会话

如需向用户显示其他应用中特定会话的详细视图,您的应用可以调用包含会话信息的 intent。您可以指定特定应用,例如创建会话的应用。或者,如果设备上未安装创建会话的应用,您可以允许任何可显示健身活动的应用响应 intent。

如需创建 intent 以在其他应用上显示会话数据,请使用 SessionsApi.ViewIntentBuilder 类:

Kotlin

// Pass your activity object to the constructor
val intent = SessionsApi.ViewIntentBuilder(this)
    .setPreferredApplication("com.example.someapp") // optional
    .setSession(session)
    .build()

// Invoke the intent
startActivity(intent)

Java

// Pass your activity object to the constructor
Intent intent = new SessionsApi.ViewIntentBuilder(this)
        .setPreferredApplication("com.example.someapp") // optional
        .setSession(session)
        .build();

// Invoke the intent
startActivity(intent);

接收来自其他应用的 intent

如需注册您的应用以接收来自其他健康与保健应用的 intent,请在清单中声明类似于以下内容的 intent 过滤器:

<intent-filter>
    <action android:name="vnd.google.fitness.VIEW"/>
    <data android:mimeType="vnd.google.fitness.session/running"/>
</intent-filter>

您的应用从 Google 健身收到的每个 intent 都只能是一个 activity,但您可以在单个 intent 过滤器中过滤多种 MIME 类型。应用的 intent 过滤器需要包含应用支持的所有 activity。

健身 intent 包括以下 extra:

  • vnd.google.gms.fitness.start_time
  • vnd.google.gms.fitness.end_time
  • vnd.google.gms.fitness.session

您可以从这些 extra 中获取数据,如下所示:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ...
    val supportedType = Session.getMimeType(FitnessActivities.RUNNING)

    if (Intent.ACTION_VIEW == intent.action && supportedType == intent.type) {
        // Get the intent extras
        val startTime = Fitness.getStartTime(intent, TimeUnit.MILLISECONDS);
        val endTime = Fitness.getEndTime(intent, TimeUnit.MILLISECONDS)
        val session = Session.extract(intent)
    }
}

Java

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...

    String supportedType = Session.getMimeType(FitnessActivities.RUNNING);

    if (Intent.ACTION_VIEW.equals(getIntent().getAction()) && supportedType.equals(getIntent().getType())) {
        // Get the intent extras
        long startTime = Fitness.getStartTime(getIntent(), TimeUnit.MILLISECONDS);
        long endTime = Fitness.getEndTime(getIntent(), TimeUnit.MILLISECONDS);
        Session session = Session.extract(getIntent());
    }
}