ניווט במסלול עם מספר יעדים

אפשר להיעזר במדריך הזה כדי לשרטט מסלול בתוך האפליקציה למספר יעדים, שנקראות גם 'ציוני דרך', באמצעות ה-Navigation SDK עבור Android.

סקירה כללית

  1. לשלב את Navigation SDK באפליקציה, שמתואר במאמר הגדרת הפרויקט.
  2. הוספת SupportNavigationFragment או NavigationView לאפליקציה. הרכיב הזה בממשק המשתמש מוסיף לפעילות שלכם את המפה האינטראקטיבית ואת ממשק המשתמש לניווט המפורט.
  3. משתמשים במחלקה NavigationApi כדי להפעיל את ה-SDK.
  4. מגדירים Navigator כדי לשלוט בניווט עם מסלול מפורט:

    • מוסיפים יעדים באמצעות setDestinations().
    • מתחילים לנווט באמצעות startGuidance().
    • משתמשים ב-getSimulator() כדי לדמות את ההתקדמות לאורך המסלול, לצורך בדיקה, ניפוי באגים והדגמה של אפליקציה.
  5. יצירה והפעלה של האפליקציה.

להצגת הקוד

הוספת שבר ניווט

SupportNavigationFragment הוא הרכיב בממשק המשתמש שמציג הפלט החזותי של הניווט, כולל מפה אינטראקטיבית ומסלול מפורט לקבלת מסלול. אפשר להצהיר על המקטע בקובץ פריסת ה-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().

כחלופה למקטע, רכיב ממשק המשתמש זמין גם 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;
                }
            }
        }
    }
    

אתחול ה-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() קריאה חוזרת (callback) כדי להתחיל בניווט כשהניווט מוכן:

    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. צריך להוסיף שיטה כדי ליצור אובייקט 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. הגדרת כל נקודות הדרך לנסיעה הזו. (לתשומת ליבכם: ייתכן שתקבלו הודעת שגיאה אם משתמשים במזהי מקומות שעבורם הניווט לא יכול לשרטט מסלול. הדוגמה במדריך הזה נעשה שימוש במזהי מקומות לציון ציוני דרך באוסטרליה. לצפייה בהערות בהמשך המאמר איך מקבלים מזהים של מקומות שונים). לאחר החישוב מסלול, 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 למחשב. פועלים לפי הוראות להפעלת אפשרויות למפתחים ב-Android את המכשיר ולהגדיר את המערכת לזהות אותו. (לחלופין, אפשר להשתמש ניהול מכשיר וירטואלי (AVD) של Android כדי להגדיר מכשיר וירטואלי במכשיר. כאשר בוחרים אמולטור, חשוב לבחור תמונה שכוללת ממשקי ה-API של Google).
  2. ב-Android Studio, לוחצים על אפשרות התפריט הפעלה (או על סמל לחצן ההפעלה). בוחרים מכשיר בהתאם להנחיה.

טיפים לשיפור חוויית המשתמש

  • המשתמש חייב לאשר את התנאים וההגבלות של ניווט ב-Google לפני הניווט יהיה זמין. האישור הזה נדרש רק פעם אחת. על ידי כברירת מחדל, ה-SDK מבקש לאשר בפעם הראשונה שהניווט הופעלה. אם אתם מעדיפים, תוכלו להפעיל את תיבת הדו-שיח 'תנאים והגבלות של הניווט'. בשלב מוקדם של תהליך חוויית המשתמש באפליקציה, למשל במהלך ההרשמה או ההתחברות, showTermsAndConditionsDialog()
  • איכות הניווט ומידת הדיוק של זמן ההגעה המשוער השתפרו באופן משמעותי אם משתמשים מזהי מקום כדי לאתחל ציון דרך, ולא קו אורך/רוחב היעד.
  • הדוגמה הזו מסיקה את ציוני הדרך ממקום ספציפי המזהים. דרכים נוספות לקבלת מזהה מקום: