複数の目的地のルートを確認する

このガイドでは、Navigation SDK for Android を使用して、アプリ内の複数の目的地(ウェイポイント)へのルートをプロットします。

概要

  1. プロジェクトをセットアップするの説明に沿って、Navigation SDK をアプリに統合します。
  2. アプリに SupportNavigationFragment または NavigationView を追加します。この UI 要素は、インタラクティブな地図とターンバイターン方式のナビゲーション UI をアクティビティに追加します。
  3. NavigationApi クラスを使用して SDK を初期化します。
  4. ターンバイターン ナビゲーションを制御する Navigator を定義します。

    • setDestinations() を使用してデスティネーションを追加します。
    • startGuidance() でナビゲーションを開始します。
    • getSimulator() を使用して、アプリのテスト、デバッグ、デモ用に、ルート上の車両の進行をシミュレートします。
  5. アプリをビルドして実行します。

コードの確認

ナビゲーション フラグメントを追加する

SupportNavigationFragment は、インタラクティブな地図やターンバイターンのルート案内など、ナビゲーションのビジュアル出力を表示する UI コンポーネントです。次のように、XML レイアウト ファイルでフラグメントを宣言できます。

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    android:name="com.google.android.libraries.navigation.SupportNavigationFragment"
    android:id="@+id/navigation_fragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

または、Android のドキュメントに記載されているとおり、FragmentActivity.getSupportFragmentManager() を使用して、フラグメントをプログラムで作成することもできます。

フラグメントの代わりに、UI コンポーネントを NavigationView として使用することもできます。クラスの説明の上部にある情報、特にライフサイクル メソッドを転送するための要件に注意してください。

位置情報の利用許可をリクエストする

デバイスの位置を特定するには、アプリで位置情報の利用許可をリクエストする必要があります。

このチュートリアルでは、精度の高い位置情報の利用許可をリクエストするためのコードを提供します。 詳しくは、Android の権限に関するガイドをご覧ください。

  1. 権限を <manifest> 要素の子要素として Android マニフェストに追加します。

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.navsdkmultidestination">
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    </manifest>
    
  2. アプリで実行時の権限をリクエストして、ユーザーが位置情報の利用許可を許可または拒否できるようにします。ユーザーが高精度の位置情報の利用許可を付与しているかどうかは、次のコードで確認できます。許可していない場合は、パーミッションをリクエストします。

    if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
            android.Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
        mLocationPermissionGranted = true;
    } else {
        ActivityCompat.requestPermissions(this,
                new String[] { android.Manifest.permission.ACCESS_FINE_LOCATION },
                PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
    }
    
    if (!mLocationPermissionGranted) {
        displayMessage("Error loading Navigation SDK: "
                + "The user has not granted location permission.", DISPLAY_BOTH);
        return;
    }
    
  3. 権限リクエストの結果を処理するように onRequestPermissionsResult() コールバックをオーバーライドします。

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
                                           @NonNull int[] grantResults) {
        mLocationPermissionGranted = false;
        switch (requestCode) {
            case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
                // If request is canceled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    mLocationPermissionGranted = true;
                }
            }
        }
    }
    

Navigation SDK を初期化してジャーニーを設定する

NavigationApi クラスは、アプリが Google ナビゲーションを使用することを承認する初期化ロジックを提供します。Navigator クラスは、ナビゲーション ジャーニーの構成と開始/停止を制御します。

  1. 画面とログにメッセージを表示するヘルパー メソッドを作成します。

    private void displayMessage(String errorMessage, String displayMedium) {
        if (displayMedium.equals(DISPLAY_BOTH) || displayMedium.equals(DISPLAY_TOAST)) {
            Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show();
        }
    
        if (displayMedium.equals(DISPLAY_BOTH) || displayMedium.equals(DISPLAY_LOG)) {
            Log.d(TAG, errorMessage);
        }
    }
    
  2. Navigation SDK を初期化し、ナビゲータの準備が整ったらナビゲーションを開始するように onNavigatorReady() コールバックをオーバーライドします。

    NavigationApi.getNavigator(this, new NavigationApi.NavigatorListener() {
                /**
                 * Sets up the navigation UI when the navigator is ready for use.
                 */
                @Override
                public void onNavigatorReady(Navigator navigator) {
                    displayMessage("Navigator ready.", DISPLAY_BOTH);
                    mNavigator = navigator;
                    mNavFragment = (SupportNavigationFragment) getFragmentManager()
                            .findFragmentById(R.id.navigation_fragment);
    
                    // Set the camera to follow the device location with 'TILTED' driving view.
                    mNavFragment.getCamera().followMyLocation(Camera.Perspective.TILTED);
    
                    // Navigate to the specified places.
                    navigateToPlaces();
                }
    
                /**
                 * Handles errors from the Navigation SDK.
                 * @param errorCode The error code returned by the navigator.
                 */
                @Override
                public void onError(@NavigationApi.ErrorCode int errorCode) {
                    switch (errorCode) {
                        case NavigationApi.ErrorCode.NOT_AUTHORIZED:
                            displayMessage("Error loading Navigation SDK: Your API key is "
                                    + "invalid or not authorized to use the Navigation SDK.",
                                    DISPLAY_BOTH);
                            break;
                        case NavigationApi.ErrorCode.TERMS_NOT_ACCEPTED:
                            displayMessage("Error loading Navigation SDK: User did not accept "
                                    + "the Navigation Terms of Use.", DISPLAY_BOTH);
                            break;
                        case NavigationApi.ErrorCode.NETWORK_ERROR:
                            displayMessage("Error loading Navigation SDK: Network error.",
                                    DISPLAY_BOTH);
                            break;
                        case NavigationApi.ErrorCode.LOCATION_PERMISSION_MISSING:
                            displayMessage("Error loading Navigation SDK: Location permission "
                                    + "is missing.", DISPLAY_BOTH);
                            break;
                        default:
                            displayMessage("Error loading Navigation SDK: " + errorCode,
                                    DISPLAY_BOTH);
                    }
                }
            });
    
  3. 指定されたプレイス ID とタイトルから Waypoint オブジェクトを作成するメソッドを追加します。

    private void createWaypoint(String placeId, String title) {
        try {
            mWaypoints.add(
              Waypoint.builder()
                     .setPlaceIdString(placeId)
                     .setTitle(title)
                     .build()
            );
        } catch (Waypoint.UnsupportedPlaceIdException e) {
            displayMessage("Error starting navigation: Place ID is not supported: " + placeId,
                    DISPLAY_BOTH);
        }
    }
    
  4. 各地点までの計算された移動時間と距離を表示するメソッドを追加します。

    private void displayTimesAndDistances() {
        List<TimeAndDistance> timesAndDistances = mNavigator.getTimeAndDistanceList();
        int leg = 1;
        String message = "You're on your way!";
        for (TimeAndDistance timeAndDistance : timesAndDistances) {
            message = message + "\nRoute leg: " + leg++
                    + ": Travel time (seconds): " + timeAndDistance.getSeconds()
                    + ". Distance (meters): " + timeAndDistance.getMeters();
        }
        displayMessage(message, DISPLAY_BOTH);
    }
    
  5. この行程のすべての地点を設定します。(プレイス ID を使用すると、ナビゲータがルートをプロットできない場合、エラーが発生することがあります)。このチュートリアルのサンプルアプリでは、オーストラリアのウェイポイントにプレイス ID を使用しています。異なるプレイス ID の取得に関する下記の注をご覧ください)。ルートを計算すると、SupportNavigationFragment によって、ルートを表すポリラインが地図上に表示され、各地点にマーカーが表示されます。

    private void navigateToPlaces() {
    
        // Set up a waypoint for each place that we want to go to.
        createWaypoint("ChIJq6qq6jauEmsRJAf7FjrKnXI", "Sydney Star");
        createWaypoint("ChIJ3S-JXmauEmsRUcIaWtf4MzE", "Sydney Opera House");
        createWaypoint("ChIJLwgLFGmuEmsRzpDhHQuyyoU", "Sydney Conservatorium of Music");
    
        // If this journey is already in progress, no need to restart navigation.
        // This can happen when the user rotates the device, or sends the app to the background.
        if (mSavedInstanceState != null
                && mSavedInstanceState.containsKey(KEY_JOURNEY_IN_PROGRESS)
                && mSavedInstanceState.getInt(KEY_JOURNEY_IN_PROGRESS) == 1) {
            return;
        }
    
        // Create a future to await the result of the asynchronous navigator task.
        ListenableResultFuture<Navigator.RouteStatus> pendingRoute =
                mNavigator.setDestinations(mWaypoints);
    
        // Define the action to perform when the SDK has determined the route.
        pendingRoute.setOnResultListener(
                new ListenableResultFuture.OnResultListener<Navigator.RouteStatus>() {
                    @Override
                    public void onResult(Navigator.RouteStatus code) {
                        switch (code) {
                            case OK:
                                mJourneyInProgress = true;
                                // Hide the toolbar to maximize the navigation UI.
                                if (getActionBar() != null) {
                                    getActionBar().hide();
                                }
    
                                // Register some listeners for navigation events.
                                registerNavigationListeners();
    
                                // Display the time and distance to each waypoint.
                                displayTimesAndDistances();
    
                                // Enable voice audio guidance (through the device speaker).
                                mNavigator.setAudioGuidance(
                                        Navigator.AudioGuidance.VOICE_ALERTS_AND_GUIDANCE);
    
                                // Simulate vehicle progress along the route for demo/debug builds.
                                if (BuildConfig.DEBUG) {
                                    mNavigator.getSimulator().simulateLocationsAlongExistingRoute(
                                            new SimulationOptions().speedMultiplier(5));
                                }
    
                                // Start turn-by-turn guidance along the current route.
                                mNavigator.startGuidance();
                                break;
                            // Handle error conditions returned by the navigator.
                            case NO_ROUTE_FOUND:
                                displayMessage("Error starting navigation: No route found.",
                                        DISPLAY_BOTH);
                                break;
                            case NETWORK_ERROR:
                                displayMessage("Error starting navigation: Network error.",
                                        DISPLAY_BOTH);
                                break;
                            case ROUTE_CANCELED:
                                displayMessage("Error starting navigation: Route canceled.",
                                        DISPLAY_BOTH);
                                break;
                            default:
                                displayMessage("Error starting navigation: "
                                        + String.valueOf(code), DISPLAY_BOTH);
                        }
                    }
                });
    }
    

アプリをビルドして実行する

  1. Android デバイスをコンピュータに接続します。instructionsに沿って、Android デバイスでデベロッパー オプションを有効にし、デバイスを検出するようにシステムを設定します(または、Android Virtual Device(AVD)Manager を使用して仮想デバイスを設定することもできます。エミュレータを選択するときは、Google API を含むイメージを選択する必要があります)。
  2. Android Studio で [Run] メニュー オプション(またはプレイボタン アイコン)をクリックします。表示される指示に沿ってデバイスを選択します。

ユーザー エクスペリエンスを向上させるためのヒント

  • ナビゲーションが利用可能になる前に、ユーザーは Google Navigation 利用規約に同意する必要があります。この承認が必要なのは 1 回のみです。デフォルトでは、ナビゲータが初めて呼び出されたときに、承認を求めるメッセージが SDK に表示されます。ナビゲーション利用規約ダイアログは、登録時やログイン時など、アプリの UX フローの早い段階で showTermsAndConditionsDialog() を使用してトリガーできます。
  • 緯度と経度の目的地ではなくプレイス ID を使用して地点を初期化すると、ナビゲーションの品質と到着予定時刻の精度が大幅に向上します。
  • このサンプルは、特定のプレイス ID から地点を取得します。プレイス ID は、他にも次のような方法で取得できます。