Работа с сессиями

Сеансы представляют собой интервал времени, в течение которого пользователи выполняют фитнес-занятия. API сеансов позволяет вашему приложению создавать сеансы в фитнес-магазине.

Для текущих занятий фитнесом, когда пользователь уведомляет ваше приложение о начале и завершении занятия фитнесом, вы можете создавать сеансы в режиме реального времени.

Вы также можете вставить тренировку в фитнес-магазин после ее завершения или при импорте данных и сессий из-за пределов Google Fit.

Создавайте сеансы в режиме реального времени

Чтобы создать сеансы для текущих занятий фитнесом, выполните следующие действия:

  1. Подпишитесь на данные о фитнесе с помощью метода RecordingClient.subscribe .

  2. Запустите сеанс с помощью метода SessionsClient.startSession , когда пользователь инициирует фитнес-занятие.

  3. Остановите сеанс с помощью метода SessionsClient.stopSession , когда пользователь завершает фитнес-тренировку.

  4. Отмените подписку на данные о фитнесе , которые вам больше не интересны, используя метод RecordingClient.unsubscribe .

Начать сеанс

Чтобы запустить сеанс в вашем приложении, используйте метод SessionsClient.startSession :

Котлин

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

Джава

// 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 :

Котлин

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

Джава

// 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 .

  • Имя: имя в объекте Session , которое вы передаете SessionsClient.startSession .

Вставьте занятия в фитнес-магазин

Чтобы вставить сеансы с ранее собранными вами данными, выполните следующие действия:

  1. Создайте объект Session , указывающий временной интервал и другую необходимую информацию.

  2. Создайте SessionInsertRequest с сеансом.

  3. При необходимости добавьте наборы данных и агрегируйте точки данных.

  4. Вставьте сеанс, используя метод SessionsClient.insertSession .

Вставить сеанс

Чтобы вставить данные о фитнесе, содержащие метаданные сеанса, в историю фитнеса пользователя, сначала создайте экземпляр SessionInsertRequest :

Котлин

// 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()

Джава

// 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 , а затем создавался сеанс.

Котлин

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

Джава

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 Fit показывают, какие занятия фитнесом пользователи выполняют в течение заданного интервала времени. Данные сегментов активности имеют тип com.google.activity.segment ( TYPE_ACTIVITY_SEGMENT ) и особенно полезны для поддержки пауз во время тренировок.

Например, если вы создаете 30-минутный сеанс работы с помощью метода Session.Builder.setActivity() , но между ними пользователь делает 10-минутный перерыв, ваше приложение неправильно покажет, что пользователь работал в течение 30 минут. При условии, что ваше приложение может определить, шел ли пользователь или бегал, данные сегмента активности позволяют вашему приложению указать, что пользователь бежал 10 минут, шел 10 минут, а затем бежал еще 10 минут. Другие приложения также могут правильно сообщать об активности, просматривая вставленные вами данные сегмента активности.

Чтобы добавить данные сегмента активности в сеанс, создайте набор данных, содержащий точки типа com.google.activity.segment . Каждая из этих точек представляет собой непрерывный интервал времени, в течение которого пользователь выполнял один тип активности.

Для предыдущего примера бега и ходьбы потребуются три точки сегмента активности: одна для бега в течение первых 10 минут, одна для ходьбы в течение следующих 10 минут и одна для бега в течение последних 10 минут.

Котлин

// 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()

Джава

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

Чтение данных о фитнесе с помощью сеансов

API сеансов позволяет получить список сеансов из фитнес-магазина, соответствующих некоторым критериям. Например, вы можете получить все сеансы, содержащиеся в интервале времени, или получить конкретный сеанс по имени или идентификатору. Вы также можете указать, интересны ли вам сеансы, созданные вашим приложением или любым другим приложением.

Чтобы получить список сеансов, соответствующих некоторым критериям, сначала создайте экземпляр SessionReadRequest :

Котлин

// 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()

Джава

// 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 :

Котлин

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

Джава

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

Чтение данных сна с помощью сеансов

Сеансы сна рассматриваются отдельно от других сеансов активности. По умолчанию ответы на чтение содержат только сеансы активности, а не сеансы сна.

Чтобы включить сеансы сна, используйте метод includeSleepSessions при создании SessionReadRequest . Чтобы включить как действия, так и сеансы, используйте includeSleepSessions и includeActivitySessions .

Показывать сеансы в других приложениях

Чтобы показать пользователям более подробное представление определенного сеанса в другом приложении, ваше приложение может вызвать намерение, содержащее информацию о сеансе. Вы можете указать конкретное приложение, например приложение, создавшее сеанс. Или, если приложение, создавшее сеанс, не установлено на устройстве, вы можете разрешить любому приложению, которое может отображать занятия фитнесом, реагировать на намерение.

Чтобы создать намерение отображать данные сеанса в другом приложении, используйте класс SessionsApi.ViewIntentBuilder :

Котлин

// 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)

Джава

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

Каждое намерение, которое ваше приложение получает от Google Fit, относится только к одному действию, но вы можете фильтровать несколько типов MIME в одном фильтре намерений. Фильтр намерений вашего приложения должен включать все действия, которые поддерживает ваше приложение.

Фитнес-намерения включают в себя следующие дополнения:

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

Вы можете получить данные из этих дополнений следующим образом:

Котлин

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

Джава

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