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)
    

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

ルートが不要になったら、アプリがルートのフォローを停止するようにします。たとえば、ドライバーがバックエンドでルートを COMPLETE とマークした場合などです。ルートの共有を停止すると、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 有効な認証情報がない場合にこのエラーが発生します。 たとえば、ルート ID なしで JWT トークンが署名されている場合や、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 トークンが原因でリクエストの認証に失敗しました。このエラーは、ルート ID なしで JWT トークンが署名されている場合、または JWT トークンの有効期限が切れている場合に発生します。