Di chuyển trong tuyến đường đa điểm đến

Hãy làm theo hướng dẫn này để vẽ một tuyến đường trong ứng dụng của bạn đến nhiều đích đến (còn gọi là điểm tham chiếu) bằng Navigation SDK cho Android.

Tổng quan

  1. Tích hợp Navigation SDK vào ứng dụng của bạn, như mô tả trong phần Thiết lập dự án.
  2. Thêm một SupportNavigationFragment hoặc NavigationView vào ứng dụng của bạn. Phần tử giao diện người dùng này sẽ thêm bản đồ tương tác và giao diện người dùng chỉ đường từng chặng vào hoạt động của bạn.
  3. Sử dụng lớp NavigationApi để khởi chạy SDK.
  4. Xác định Navigator để kiểm soát chế độ chỉ đường từng chặng:

    • Thêm đích đến bằng cách sử dụng setDestinations().
    • Bắt đầu đi theo chỉ dẫn bằng cách nhấn vào biểu tượng startGuidance().
    • Sử dụng getSimulator() để mô phỏng tiến trình của xe dọc theo tuyến đường, nhằm mục đích kiểm thử, gỡ lỗi và minh hoạ ứng dụng của bạn.
  5. Tạo bản dựng và chạy ứng dụng của bạn.

Xem mã

Thêm một mảnh điều hướng

SupportNavigationFragment là thành phần giao diện người dùng hiển thị đầu ra trực quan của hoạt động điều hướng, bao gồm cả bản đồ tương tác và chỉ dẫn từng chặng. Bạn có thể khai báo mảnh trong tệp bố cục XML như minh hoạ bên dưới:

<?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"/>

Ngoài ra, bạn có thể tạo mảnh theo phương thức lập trình, như mô tả trong tài liệu Android, bằng cách sử dụng FragmentActivity.getSupportFragmentManager().

Ngoài mảnh, thành phần giao diện người dùng cũng có sẵn dưới dạng NavigationView. Trong hầu hết các trường hợp, bạn nên sử dụng SupportNavigationFragment (một trình bao bọc cho NavigationView) thay vì tương tác trực tiếp với NavigationView. Để biết thêm thông tin, hãy xem Các phương pháp hay nhất về hoạt động tương tác với bản đồ điều hướng .

Yêu cầu cấp quyền vị trí

Ứng dụng của bạn phải yêu cầu quyền truy cập thông tin vị trí để xác định vị trí của thiết bị.

Hướng dẫn này cung cấp mã bạn cần để yêu cầu quyền truy cập vị trí chính xác. Để biết thêm thông tin, hãy xem hướng dẫn về các quyền trên Android.

  1. Thêm quyền này làm phần tử con của phần tử <manifest> trong tệp kê khai 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. Yêu cầu cấp quyền khi bắt đầu chạy trong ứng dụng của bạn, cho phép người dùng có cơ hội cho phép hoặc từ chối quyền truy cập vào vị trí. Đoạn mã sau đây kiểm tra xem người dùng đã cấp quyền truy cập thông tin vị trí chính xác hay chưa. Nếu chưa, ứng dụng sẽ yêu cầu cấp quyền:

        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. Ghi đè lệnh gọi lại onRequestPermissionsResult() để xử lý kết quả của yêu cầu cấp quyền:

        @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;
                    }
                }
            }
        }
    

Khởi chạy Navigation SDK và định cấu hình một hành trình

Lớp NavigationApi cung cấp logic khởi tạo cho phép ứng dụng của bạn sử dụng tính năng chỉ đường của Google. Lớp Navigator cung cấp quyền kiểm soát đối với việc định cấu hình, bắt đầu và dừng hành trình điều hướng.

  1. Tạo một phương thức trợ giúp để hiện thông báo trên màn hình và trong nhật ký.

        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. Khởi chạy Navigation SDK và ghi đè lệnh gọi lại onNavigatorReady() để bắt đầu quy trình chỉ đường khi trình điều hướng đã sẵn sàng:

        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. Thêm một phương thức để tạo đối tượng Waypoint từ mã nhận dạng và tiêu đề của một địa điểm nhất định.

        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. Thêm một phương thức để hiển thị thời gian và khoảng cách di chuyển đã tính toán đến từng điểm đánh dấu.

        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. Đặt tất cả các điểm tham chiếu cho hành trình này. (Xin lưu ý rằng bạn có thể gặp lỗi nếu sử dụng mã địa điểm mà trình điều hướng không thể vẽ tuyến đường. Ứng dụng mẫu trong hướng dẫn này sử dụng mã địa điểm cho các điểm tham chiếu ở Úc. Xem các ghi chú bên dưới về cách lấy các mã địa điểm khác nhau.) Sau khi tính toán chỉ đường, SupportNavigationFragment sẽ hiển thị một đường nhiều đường biểu thị tuyến đường trên bản đồ, với một điểm đánh dấu tại mỗi điểm tham chiếu.

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

Tạo và chạy ứng dụng

  1. Kết nối thiết bị Android với máy tính. Làm theo hướng dẫn để bật tuỳ chọn cho nhà phát triển trên thiết bị Android và định cấu hình hệ thống để phát hiện thiết bị. (Ngoài ra, bạn có thể dùng Trình quản lý thiết bị ảo Android (AVD) để định cấu hình một thiết bị ảo. Khi chọn trình mô phỏng, hãy nhớ chọn một hình ảnh có chứa các API của Google.)
  2. Trong Android Studio, hãy nhấp vào lựa chọn Run (Chạy) trong trình đơn (hoặc biểu tượng nút phát). Chọn một thiết bị theo lời nhắc.

Gợi ý để cải thiện trải nghiệm người dùng

  • Người dùng phải chấp nhận Điều khoản dịch vụ của Google Maps thì mới có thể sử dụng tính năng chỉ đường. Bạn chỉ cần chấp nhận một lần. Theo mặc định, SDK sẽ nhắc bạn chấp nhận lần đầu tiên trình điều hướng được gọi. Nếu muốn, bạn có thể kích hoạt hộp thoại Điều khoản dịch vụ của tính năng chỉ đường ở giai đoạn đầu trong luồng trải nghiệm người dùng của ứng dụng, chẳng hạn như trong quá trình đăng ký hoặc đăng nhập, bằng cách sử dụng showTermsAndConditionsDialog().
  • Chất lượng chỉ đường và độ chính xác của thời gian đến dự kiến được cải thiện đáng kể nếu bạn sử dụng mã địa điểm để khởi tạo một điểm tham chiếu, thay vì đích đến là vĩ độ/kinh độ.
  • Mẫu này lấy các điểm tham chiếu từ mã địa điểm cụ thể. Sau đây là những cách khác để lấy mã địa điểm:

  • Sử dụng công cụ tìm mã địa điểm để lấy mã địa điểm cho các vị trí cụ thể.

  • Sử dụng Geocoding API để tìm mã địa điểm cho một địa chỉ nhất định. API Geocoding hoạt động hiệu quả nếu bạn có địa chỉ đầy đủ, rõ ràng cho các điểm tham chiếu. Xem hướng dẫn về các phương pháp hay nhất để chuyển đổi địa chỉ thành toạ độ địa lý.

  • Sử dụng tìm kiếm văn bản bằng Places API để tìm mã địa điểm cho một địa chỉ nhất định. Places API hoạt động hiệu quả nếu bạn có địa chỉ không đầy đủ hoặc không rõ ràng cho các điểm tham chiếu. Xem hướng dẫn về các phương pháp hay nhất để chuyển đổi địa chỉ thành toạ độ địa lý.