Android でルートをフォローする

プラットフォームを選択: Android iOS JavaScript

ルートをフォローすると、ユーザーアプリに適切な車両の位置が表示されます。そのため、アプリはルートのフォローを開始し、ルートの進行状況を更新し、ルートが完了したらフォローを停止する必要があります。

このドキュメントでは、そのプロセスの仕組みについて説明します。

始める前に

次のことを確認してください。

  • ユーザーアプリのバックエンド サービスが設定され、コンシューマーと車両をマッチングするサービスが稼働している。

  • アプリの地図を設定している

ルートのフォローを開始する

バックエンド サーバーがコンシューマーと車両をマッチングしたら、JourneySharingSession を使用してルートのフォローを開始します。

次のサンプルコードは、ビューの読み込み後にルートのフォローを開始する方法を示しています。

Java

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

Kotlin

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 オブジェクトにリスナーを登録します。

    Java

    // 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) {
          // ...
    }
    
    // ...
    });
    

    Kotlin

    // 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 を使用して、ルートのリスナーを構成します。

    Java

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

    Kotlin

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

ルートのフォローを停止する

ルートが不要になったら(ドライバーがバックエンドでルートを完了としてマークした場合など)、アプリがルートのフォローを停止するようにしてください。ルートの共有を停止すると、Fleet Engine への不要なネットワーク リクエストを回避し、メモリリークを防ぐことができます。

次のサンプルコードに示すように、JourneySharingSession を使用してルートのフォローを停止します。

Java

public class MainActivity extends AppCompatActivity
    implements ConsumerViewModel.JourneySharingListener  {

  // Class implementation

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

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

Kotlin

class SampleAppActivity : AppCompatActivity(), ConsumerViewModel.JourneySharingListener {

  // Class implementation

  override fun onDestroy() {
    super.onDestroy()

    journeySharingSession?.stop()
  }
}

ルートのエラーを処理する

onTripRefreshError メソッドは、ルートのモニタリング中に発生したエラーを表示します。エラー メッセージは Google Cloud エラー標準に準拠しています。エラー メッセージの定義とすべてのエラーコードについて詳しくは、Google Cloud エラー のドキュメントをご覧ください。

ルートのモニタリング中に発生する一般的なエラーをいくつか示します。

HTTP RPC 説明
400 INVALID_ARGUMENT クライアントが無効なルート名を指定しました。ルート名は 形式 providers/{provider_id}/trips/{trip_id} に従う必要があります。 provider_id は、サービス プロバイダが所有する Cloud プロジェクトの ID である必要があります。
401 UNAUTHENTICATED 有効な認証情報がない場合にこのエラーが発生します。 たとえば、JWT トークンがルート ID なしで署名されている場合や、JWT トークン の有効期限が切れている場合などです。
403 PERMISSION_DENIED クライアントに十分な権限がない場合 (コンシューマー ロールのユーザーが updateTrip を呼び出そうとした場合など)、JWT トークンが無効な場合、またはクライアント プロジェクトで API が有効になっていない場合に、このエラーが発生します。 JWT トークンがないか、リクエストされたルート ID と一致しないルート ID でトークンが署名されている可能性があります。
429 RESOURCE_EXHAUSTED リソース割り当てがゼロであるか、トラフィック レートが上限を超えています。
503 UNAVAILABLE サービス利用不可。通常、サーバーがダウンしています。
504 DEADLINE_EXCEEDED リクエスト期限を超えました。このエラーは、呼び出し元が、メソッドのデフォルト期限よりも短い期限を設定し(つまり、 要求された期限はサーバーがリクエストを処理するのに十分ではない)、 リクエストがその期限内に完了しなかった場合にのみ発生します。

Consumer SDK のエラーを処理する

Consumer SDK は、コールバック メカニズムを使用して、ルートの更新エラーをユーザーアプリに送信します。コールバック パラメータは、プラットフォーム固有の戻り値の型( TripUpdateError Android の場合、 NSError iOS の場合)です。

ステータス コードを抽出する

コールバックに渡されるエラーは通常 gRPC エラーであり、ステータス コードの形式で追加情報を抽出することもできます。ステータス コードの 完全なリストについては、 gRPC でのステータス コードとその使用をご覧ください。

Java

エラーの詳細を示す gRPC ステータス コードを、TripUpdateError から返された onTripUpdateError() から抽出できます 。

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

Kotlin

エラーの詳細を示す gRPC ステータス コードを、TripUpdateError から返された onTripUpdateError() から抽出できます 。

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

ステータス コードを解釈する

ステータス コードは、サーバーとネットワーク関連のエラーとクライアントサイドのエラーの 2 種類のエラーをカバーします。

サーバーとネットワークのエラー

次のステータス コードは、ネットワーク エラーまたはサーバーエラーを示します。これらのエラーを解決するための対応は必要ありません。Consumer SDK は自動的に復旧します。

ステータス コード説明
ABORTED サーバーがレスポンスの送信を停止しました。通常、これは サーバーの問題が原因です。
CANCELLED サーバーが送信レスポンスを終了しました。通常、これはアプリがバックグラウンドに送信された場合、またはユーザーアプリの状態が変更された場合に発生します。

INTERRUPTED
DEADLINE_EXCEEDED サーバーからの応答に時間がかかりすぎました。
UNAVAILABLE サーバーが利用できませんでした。通常、これはネットワーク の問題が原因です。

クライアントエラー

次のステータス コードはクライアント エラーを示します。これらのエラーを解決するには対応が必要です。Consumer SDK は、ルートの共有を終了するまでルートの更新を再試行しますが、対応するまで復旧しません。

ステータス コード説明
INVALID_ARGUMENT ユーザーアプリが無効なルート名を指定しました。ルート名は providers/{provider_id}/trips/{trip_id} の形式にする必要があります。
NOT_FOUND ルートが作成されていません。
PERMISSION_DENIED ユーザーアプリに十分な権限がありません。このエラーは、次の場合に発生します。
  • ユーザーアプリに権限がない
  • Google Cloud コンソールでプロジェクトに対して Consumer SDK が有効になっていない。
  • JWT トークンがないか、無効である。
  • JWT トークンが、リクエストされたルートと一致しないルート ID で署名されている。
RESOURCE_EXHAUSTED リソース割り当てがゼロであるか、トラフィック フローのレートが 速度制限を超えています。
UNAUTHENTICATED 無効な JWT トークンが原因でリクエストの認証に失敗しました。この エラーは、JWT トークンがルート ID なしで署名されている場合、または JWT トークンの有効期限が切れている場合に発生します。