Следите за поездкой на Android

Выберите платформу: Android iOS JavaScript

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

В этом документе описывается, как работает этот процесс.

Прежде чем начать

Убедитесь, что вы настроили следующие вещи:

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

  • Вы настроили карту для своего приложения.

Начните следить за поездкой

Когда ваш внутренний сервер сопоставляет потребителя с транспортным средством, используйте JourneySharingSession , чтобы начать следить за поездкой.

В следующем примере кода показано, как начать отслеживать поездку после загрузки представления.

Ява

public class MainActivity extends AppCompatActivity
    implements ConsumerViewModel.JourneySharingListener  {

  // Class implementation

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

    // Create a TripModel instance to listen for updates to the trip specified by this trip name.
    String tripName = ...;
    TripModelManager tripModelManager = consumerApi.getTripModelManager();
    TripModel tripModel = tripModelManager.getTripModel(tripName);

    // Create a JourneySharingSession instance based on the TripModel.
    JourneySharingSession session = JourneySharingSession.createInstance(tripModel);

    // Add the JourneySharingSession instance on the map for updating the UI.
    consumerController.showSession(session);

    // Register for trip update events.
    tripModel.registerTripCallback(new TripModelCallback() {
      @Override
      public void onTripETAToNextWaypointUpdated(
          TripInfo tripInfo, @Nullable Long timestampMillis) {
        // ...
      }

      @Override
      public void onTripActiveRouteRemainingDistanceUpdated(
          TripInfo tripInfo, @Nullable Integer distanceMeters) {
        // ...
      }

      // ...
    });
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();

    if (journeySharingSession != null) {
      journeySharingSession.stop();
    }
  }
}

Котлин

class SampleAppActivity : AppCompatActivity(), ConsumerViewModel.JourneySharingListener {

  // Class implementation

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Create a TripModel instance to listen for updates to the trip specified by this trip name.
    val tripName = "tripName"
    val tripModelManager = consumerApi.getTripModelManager()
    val tripModel = tripModelManager.getTripModel(tripName)

    // Create a JourneySharingSession instance based on the TripModel.
    val session = JourneySharingSession.createInstance(tripModel)

    // Add the JourneySharingSession instance on the map for updating the UI.
    consumerController.showSession(session)

    // Register for trip update events.
    tripModel.registerTripCallback(
      object : TripModelCallback() {
        override fun onTripETAToNextWaypointUpdated(
          tripInfo: TripInfo,
          timestampMillis: Long?,
        ) {
          // ...
        }

        override fun onTripActiveRouteRemainingDistanceUpdated(
          tripInfo: TripInfo,
          distanceMeters: Int?,
        ) {
          // ...
        }

      // ...
    })
  }

  override fun onDestroy() {
    super.onDestroy()

    journeySharingSession?.stop()
  }
}

Обновить ход поездки

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

  1. Зарегистрируйте прослушиватель для объекта TripModel .

    Ява

    // Create a TripModel instance for listening to updates to the trip specified by this trip name.
    String tripName = ...;
    TripModelManager tripModelManager = consumerApi.getTripModelManager();
    TripModel tripModel = tripModelManager.getTripModel(tripName);
    
    // Create a JourneySharingSession instance based on the TripModel.
    JourneySharingSession session = JourneySharingSession.createInstance(tripModel);
    
    // Add the JourneySharingSession instance on the map for updating the UI.
    consumerController.showSession(session);
    
    // Register for trip update events.
    tripModel.registerTripCallback(new TripModelCallback() {
    @Override
    public void onTripETAToNextWaypointUpdated(
            TripInfo tripInfo, @Nullable Long timestampMillis) {
          // ...
    }
    
    @Override
    public void onTripActiveRouteRemainingDistanceUpdated(
            TripInfo tripInfo, @Nullable Integer distanceMeters) {
          // ...
    }
    
    // ...
    });
    

    Котлин

    // Create a TripModel instance for listening to updates to the trip specified by this trip name.
    val tripName = "tripName"
    val tripModelManager = consumerApi.getTripModelManager()
    val tripModel = tripModelManager.getTripModel(tripName)
    
    // Create a JourneySharingSession instance based on the TripModel.
    val session = JourneySharingSession.createInstance(tripModel)
    
    // Add the JourneySharingSession instance on the map for updating the UI.
    consumerController.showSession(session)
    
    // Register for trip update events.
    tripModel.registerTripCallback(
      object : TripModelCallback() {
        override fun onTripETAToNextWaypointUpdated(
          tripInfo: TripInfo,
          timestampMillis: Long?,
        ) {
          // ...
        }
    
        override fun onTripActiveRouteRemainingDistanceUpdated(
          tripInfo: TripInfo,
          distanceMeters: Int?,
        ) {
          // ...
        }
    
      // ...
    })
    
  2. Настройте прослушиватель для вашей поездки с помощью TripModelOptions .

    Ява

    // Set refresh interval to 2 seconds.
    TripModelOptions tripOptions =
          TripModelOptions.builder().setRefreshIntervalMillis(2000).build();
    tripModel.setTripModelOptions(tripOptions);
    

    Котлин

    // Set refresh interval to 2 seconds.
    val tripOptions = TripModelOptions.builder().setRefreshIntervalMillis(2000).build()
    tripModel.setTripModelOptions(tripOptions)
    

Перестаньте следить за поездкой

Убедитесь, что ваше приложение перестает следить за поездкой, когда она больше не нужна, например, когда водитель помечает поездку как ЗАВЕРШЕННАЯ на серверной стороне. Отключение совместного использования маршрутов позволяет избежать ненужных сетевых запросов к Fleet Engine и предотвращает утечки памяти.

Используйте JourneySharingSession , чтобы прекратить отслеживание поездки, как показано в следующем примере кода.

Ява

public class MainActivity extends AppCompatActivity
    implements ConsumerViewModel.JourneySharingListener  {

  // Class implementation

  @Override
  protected void onDestroy() {
    super.onDestroy();

    if (journeySharingSession != null) {
      journeySharingSession.stop();
    }
  }
}

Котлин

class SampleAppActivity : AppCompatActivity(), ConsumerViewModel.JourneySharingListener {

  // Class implementation

  override fun onDestroy() {
    super.onDestroy()

    journeySharingSession?.stop()
  }
}

Обработка ошибок в поездках

Метод onTripRefreshError выявляет ошибки, возникающие во время мониторинга поездки. Сообщения об ошибках соответствуют стандарту ошибок Google Cloud. Подробные определения сообщений об ошибках и все коды ошибок см. в документации Google Cloud Errors .

Вот некоторые распространенные ошибки, которые могут возникнуть во время мониторинга поездки:

HTTP ПКП Описание
400 INVALID_ARGUMENT Клиент указал неверное название поездки. Название поездки должно соответствовать формату providers/{provider_id}/trips/{trip_id} . Provider_id должен быть идентификатором облачного проекта, принадлежащего поставщику услуг.
401 НЕ АУТЕНТИФИЦИРОВАННЫЙ Вы получаете эту ошибку, если нет действительных учетных данных для аутентификации. Например, если токен JWT подписан без идентификатора поездки или срок действия токена JWT истек.
403 ДОСТУП ЗАПРЕЩЕН Вы получаете эту ошибку, если клиент не имеет достаточных разрешений (например, пользователь с ролью потребителя пытается вызвать updateTrip), если токен JWT недействителен или API не включен для клиентского проекта. Токен JWT может отсутствовать или токен подписан идентификатором поездки, который не соответствует запрошенному идентификатору поездки.
429 RESOURCE_EXHAUSTED Квота ресурса равна нулю или скорость трафика превышает лимит.
503 НЕДОСТУПНО Сервис недоступен. Обычно сервер не работает.
504 DEADLINE_EXCEEDED Срок запроса истек. Эта ошибка возникает только в том случае, если вызывающая сторона устанавливает крайний срок, который короче, чем крайний срок по умолчанию для метода (то есть запрошенного крайнего срока недостаточно для того, чтобы сервер обработал запрос), и запрос не был завершен в течение крайнего срока.

Обработка ошибок потребительского SDK

Consumer SDK отправляет ошибки обновления поездки потребительскому приложению с помощью механизма обратного вызова. Параметр обратного вызова — это возвращаемый тип, зависящий от платформы ( TripUpdateError в Android и NSError в iOS).

Извлечь коды состояния

Ошибки, передаваемые обратному вызову, обычно являются ошибками gRPC, и вы также можете извлечь из них дополнительную информацию в виде кода состояния. Полный список кодов состояния см. в разделе Коды состояния и их использование в gRPC .

Ява

Вы можете извлечь код состояния gRPC, предоставляющий подробную информацию об ошибке, из TripUpdateError возвращенного из onTripUpdateError() .

// Called when there is a trip update error.
@Override
public void onTripUpdateError(TripInfo tripInfo, TripUpdateError error) {
  Status.Code code = error.getStatusCode();
}

Котлин

Вы можете извлечь код состояния gRPC, предоставляющий подробную информацию об ошибке, из TripUpdateError возвращенного из onTripUpdateError() .

// Called when there is a trip update error.
override fun onTripUpdateError(tripInfo: TripInfo, error: TripUpdateError) {
  val code = error.getStatusCode()
}

Интерпретация кодов состояния

Коды состояния охватывают два типа ошибок: ошибки сервера и сети, а также ошибки на стороне клиента.

Ошибки сервера и сети

Следующие коды состояния относятся к ошибкам сети или сервера, и вам не нужно предпринимать никаких действий для их устранения. Consumer SDK автоматически восстанавливается после них.

Код состояния Описание
ПРЕРВИРОВАНО Сервер перестал отправлять ответ. Обычно это вызвано проблемой сервера.
ОТМЕНЕНО Сервер прервал исходящий ответ. Обычно это происходит, когда
приложение отправляется в фоновый режим или когда происходит изменение состояния в
Потребительское приложение.
ПРЕРЫВАНИЕ
DEADLINE_EXCEEDED Сервер отвечал слишком долго.
НЕДОСТУПНО Сервер был недоступен. Обычно это вызвано проблемой сети.

Ошибки клиента

Следующие коды состояния относятся к ошибкам клиента, и вам необходимо принять меры для их устранения. Consumer SDK продолжает повторять попытки обновить поездку, пока вы не завершите совместное использование поездки, но не сможет восстановиться, пока вы не предпримете соответствующие действия.

Код состояния Описание
INVALID_ARGUMENT В потребительском приложении указано неверное название поездки; Название поездки должно соответствовать формату providers/{provider_id}/trips/{trip_id} .
НЕ НАЙДЕНО Поездка так и не была создана.
ДОСТУП ЗАПРЕЩЕН У потребительского приложения недостаточно разрешений. Эта ошибка возникает, когда:
  • У потребительского приложения нет разрешений
  • Consumer SDK не включен для проекта в Google Cloud Console.
  • Токен JWT либо отсутствует, либо недействителен.
  • Токен JWT подписан идентификатором поездки, который не соответствует запрошенной поездке.
RESOURCE_EXHAUSTED Квота ресурса равна нулю, или скорость трафика превышает ограничение скорости.
НЕ АУТЕНТИФИЦИРОВАННЫЙ Запрос не прошел аутентификацию из-за недопустимого токена JWT. Эта ошибка возникает либо в том случае, если токен JWT подписан без идентификатора поездки, либо когда срок действия токена JWT истек.
,
Выберите платформу: Android iOS JavaScript

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

В этом документе описывается, как работает этот процесс.

Прежде чем начать

Убедитесь, что вы настроили следующие вещи:

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

  • Вы настроили карту для своего приложения.

Начните следить за поездкой

Когда ваш внутренний сервер сопоставляет потребителя с транспортным средством, используйте JourneySharingSession , чтобы начать следить за поездкой.

В следующем примере кода показано, как начать отслеживать поездку после загрузки представления.

Ява

public class MainActivity extends AppCompatActivity
    implements ConsumerViewModel.JourneySharingListener  {

  // Class implementation

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

    // Create a TripModel instance to listen for updates to the trip specified by this trip name.
    String tripName = ...;
    TripModelManager tripModelManager = consumerApi.getTripModelManager();
    TripModel tripModel = tripModelManager.getTripModel(tripName);

    // Create a JourneySharingSession instance based on the TripModel.
    JourneySharingSession session = JourneySharingSession.createInstance(tripModel);

    // Add the JourneySharingSession instance on the map for updating the UI.
    consumerController.showSession(session);

    // Register for trip update events.
    tripModel.registerTripCallback(new TripModelCallback() {
      @Override
      public void onTripETAToNextWaypointUpdated(
          TripInfo tripInfo, @Nullable Long timestampMillis) {
        // ...
      }

      @Override
      public void onTripActiveRouteRemainingDistanceUpdated(
          TripInfo tripInfo, @Nullable Integer distanceMeters) {
        // ...
      }

      // ...
    });
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();

    if (journeySharingSession != null) {
      journeySharingSession.stop();
    }
  }
}

Котлин

class SampleAppActivity : AppCompatActivity(), ConsumerViewModel.JourneySharingListener {

  // Class implementation

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Create a TripModel instance to listen for updates to the trip specified by this trip name.
    val tripName = "tripName"
    val tripModelManager = consumerApi.getTripModelManager()
    val tripModel = tripModelManager.getTripModel(tripName)

    // Create a JourneySharingSession instance based on the TripModel.
    val session = JourneySharingSession.createInstance(tripModel)

    // Add the JourneySharingSession instance on the map for updating the UI.
    consumerController.showSession(session)

    // Register for trip update events.
    tripModel.registerTripCallback(
      object : TripModelCallback() {
        override fun onTripETAToNextWaypointUpdated(
          tripInfo: TripInfo,
          timestampMillis: Long?,
        ) {
          // ...
        }

        override fun onTripActiveRouteRemainingDistanceUpdated(
          tripInfo: TripInfo,
          distanceMeters: Int?,
        ) {
          // ...
        }

      // ...
    })
  }

  override fun onDestroy() {
    super.onDestroy()

    journeySharingSession?.stop()
  }
}

Обновить ход поездки

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

  1. Зарегистрируйте прослушиватель для объекта TripModel .

    Ява

    // Create a TripModel instance for listening to updates to the trip specified by this trip name.
    String tripName = ...;
    TripModelManager tripModelManager = consumerApi.getTripModelManager();
    TripModel tripModel = tripModelManager.getTripModel(tripName);
    
    // Create a JourneySharingSession instance based on the TripModel.
    JourneySharingSession session = JourneySharingSession.createInstance(tripModel);
    
    // Add the JourneySharingSession instance on the map for updating the UI.
    consumerController.showSession(session);
    
    // Register for trip update events.
    tripModel.registerTripCallback(new TripModelCallback() {
    @Override
    public void onTripETAToNextWaypointUpdated(
            TripInfo tripInfo, @Nullable Long timestampMillis) {
          // ...
    }
    
    @Override
    public void onTripActiveRouteRemainingDistanceUpdated(
            TripInfo tripInfo, @Nullable Integer distanceMeters) {
          // ...
    }
    
    // ...
    });
    

    Котлин

    // Create a TripModel instance for listening to updates to the trip specified by this trip name.
    val tripName = "tripName"
    val tripModelManager = consumerApi.getTripModelManager()
    val tripModel = tripModelManager.getTripModel(tripName)
    
    // Create a JourneySharingSession instance based on the TripModel.
    val session = JourneySharingSession.createInstance(tripModel)
    
    // Add the JourneySharingSession instance on the map for updating the UI.
    consumerController.showSession(session)
    
    // Register for trip update events.
    tripModel.registerTripCallback(
      object : TripModelCallback() {
        override fun onTripETAToNextWaypointUpdated(
          tripInfo: TripInfo,
          timestampMillis: Long?,
        ) {
          // ...
        }
    
        override fun onTripActiveRouteRemainingDistanceUpdated(
          tripInfo: TripInfo,
          distanceMeters: Int?,
        ) {
          // ...
        }
    
      // ...
    })
    
  2. Настройте прослушиватель для вашей поездки с помощью TripModelOptions .

    Ява

    // Set refresh interval to 2 seconds.
    TripModelOptions tripOptions =
          TripModelOptions.builder().setRefreshIntervalMillis(2000).build();
    tripModel.setTripModelOptions(tripOptions);
    

    Котлин

    // Set refresh interval to 2 seconds.
    val tripOptions = TripModelOptions.builder().setRefreshIntervalMillis(2000).build()
    tripModel.setTripModelOptions(tripOptions)
    

Перестаньте следить за поездкой

Убедитесь, что ваше приложение перестает следить за поездкой, когда она больше не нужна, например, когда водитель помечает поездку как ЗАВЕРШЕННАЯ на серверной стороне. Отключение совместного использования маршрутов позволяет избежать ненужных сетевых запросов к Fleet Engine и предотвращает утечки памяти.

Используйте JourneySharingSession , чтобы прекратить отслеживание поездки, как показано в следующем примере кода.

Ява

public class MainActivity extends AppCompatActivity
    implements ConsumerViewModel.JourneySharingListener  {

  // Class implementation

  @Override
  protected void onDestroy() {
    super.onDestroy();

    if (journeySharingSession != null) {
      journeySharingSession.stop();
    }
  }
}

Котлин

class SampleAppActivity : AppCompatActivity(), ConsumerViewModel.JourneySharingListener {

  // Class implementation

  override fun onDestroy() {
    super.onDestroy()

    journeySharingSession?.stop()
  }
}

Обработка ошибок в поездках

Метод onTripRefreshError выявляет ошибки, возникающие во время мониторинга поездки. Сообщения об ошибках соответствуют стандарту ошибок Google Cloud. Подробные определения сообщений об ошибках и все коды ошибок см. в документации Google Cloud Errors .

Вот некоторые распространенные ошибки, которые могут возникнуть во время мониторинга поездки:

HTTP ПКП Описание
400 INVALID_ARGUMENT Клиент указал неверное название поездки. Название поездки должно соответствовать формату providers/{provider_id}/trips/{trip_id} . Provider_id должен быть идентификатором облачного проекта, принадлежащего поставщику услуг.
401 НЕ АУТЕНТИФИЦИРОВАННЫЙ Вы получаете эту ошибку, если нет действительных учетных данных для аутентификации. Например, если токен JWT подписан без идентификатора поездки или срок действия токена JWT истек.
403 ДОСТУП ЗАПРЕЩЕН Вы получаете эту ошибку, если клиент не имеет достаточных разрешений (например, пользователь с ролью потребителя пытается вызвать updateTrip), если токен JWT недействителен или API не включен для клиентского проекта. Токен JWT может отсутствовать или токен подписан идентификатором поездки, который не соответствует запрошенному идентификатору поездки.
429 RESOURCE_EXHAUSTED Квота ресурса равна нулю или скорость трафика превышает лимит.
503 НЕДОСТУПНО Сервис недоступен. Обычно сервер не работает.
504 DEADLINE_EXCEEDED Срок запроса истек. Эта ошибка возникает только в том случае, если вызывающая сторона устанавливает крайний срок, который короче, чем крайний срок по умолчанию для метода (то есть запрошенного крайнего срока недостаточно для того, чтобы сервер обработал запрос), и запрос не был завершен в течение крайнего срока.

Обработка ошибок потребительского SDK

Consumer SDK отправляет ошибки обновления поездки потребительскому приложению с помощью механизма обратного вызова. Параметр обратного вызова — это возвращаемый тип, зависящий от платформы ( TripUpdateError в Android и NSError в iOS).

Извлечь коды состояния

Ошибки, передаваемые обратному вызову, обычно являются ошибками gRPC, и вы также можете извлечь из них дополнительную информацию в виде кода состояния. Полный список кодов состояния см. в разделе Коды состояния и их использование в gRPC .

Ява

Вы можете извлечь код состояния gRPC, предоставляющий подробную информацию об ошибке, из TripUpdateError возвращенного из onTripUpdateError() .

// Called when there is a trip update error.
@Override
public void onTripUpdateError(TripInfo tripInfo, TripUpdateError error) {
  Status.Code code = error.getStatusCode();
}

Котлин

Вы можете извлечь код состояния gRPC, предоставляющий подробную информацию об ошибке, из TripUpdateError возвращенного из onTripUpdateError() .

// Called when there is a trip update error.
override fun onTripUpdateError(tripInfo: TripInfo, error: TripUpdateError) {
  val code = error.getStatusCode()
}

Интерпретация кодов состояния

Коды состояния охватывают два типа ошибок: ошибки сервера и сети, а также ошибки на стороне клиента.

Ошибки сервера и сети

Следующие коды состояния относятся к ошибкам сети или сервера, и вам не нужно предпринимать никаких действий для их устранения. Consumer SDK автоматически восстанавливается после них.

Код состояния Описание
ПРЕРВИРОВАНО Сервер перестал отправлять ответ. Обычно это вызвано проблемой сервера.
ОТМЕНЕНО Сервер прервал исходящий ответ. Обычно это происходит, когда
приложение отправляется в фоновый режим или когда происходит изменение состояния в
Потребительское приложение.
ПРЕРЫВАНИЕ
DEADLINE_EXCEEDED Сервер отвечал слишком долго.
НЕДОСТУПНО Сервер был недоступен. Обычно это вызвано проблемой сети.

Ошибки клиента

Следующие коды состояния относятся к ошибкам клиента, и вам необходимо принять меры для их устранения. Consumer SDK продолжает повторять попытки обновить поездку, пока вы не завершите совместное использование поездки, но не сможет восстановиться, пока вы не предпримете соответствующие действия.

Код состояния Описание
INVALID_ARGUMENT В потребительском приложении указано неверное название поездки; Название поездки должно соответствовать формату providers/{provider_id}/trips/{trip_id} .
НЕ НАЙДЕНО Поездка так и не была создана.
ДОСТУП ЗАПРЕЩЕН У потребительского приложения недостаточно разрешений. Эта ошибка возникает, когда:
  • У потребительского приложения нет разрешений
  • Consumer SDK не включен для проекта в Google Cloud Console.
  • Токен JWT либо отсутствует, либо недействителен.
  • Токен JWT подписан идентификатором поездки, который не соответствует запрошенной поездке.
RESOURCE_EXHAUSTED Квота ресурса равна нулю, или скорость трафика превышает ограничение скорости.
НЕ АУТЕНТИФИЦИРОВАННЫЙ Запрос не прошел аутентификацию из-за недопустимого токена JWT. Эта ошибка возникает либо в том случае, если токен JWT подписан без идентификатора поездки, либо когда срок действия токена JWT истек.