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

Сеансы представляют собой временной интервал, в течение которого пользователи выполняют фитнес-активность. 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());
    }
}