Navigator.RemainingTimeOrDistanceChangedListener
udostępnia wywołanie zwrotne onRemainingTimeOrDistanceChanged(), które jest wywoływane, gdy czas lub odległość do następnego miejsca docelowego zmieni się o więcej niż podana wartość.
Navigator.RouteChangedListener udostępnia wywołanie zwrotne
onRouteChanged(), które jest wywoływane, gdy zmienia się trasa.
Wyświetlanie kodu
Pokaż/ukryj kod Java
aktywności nawigacyjnej.
packagecom.example.navsdkmultidestination;importandroid.content.pm.PackageManager;importandroid.location.Location;importandroid.os.Bundle;importandroid.util.Log;importandroid.widget.Toast;importandroidx.annotation.NonNull;importandroidx.appcompat.app.AppCompatActivity;importandroidx.core.app.ActivityCompat;importandroidx.core.content.ContextCompat;importcom.google.android.gms.maps.GoogleMap.CameraPerspective;importcom.google.android.libraries.navigation.ArrivalEvent;importcom.google.android.libraries.navigation.ListenableResultFuture;importcom.google.android.libraries.navigation.NavigationApi;importcom.google.android.libraries.navigation.Navigator;importcom.google.android.libraries.navigation.RoadSnappedLocationProvider;importcom.google.android.libraries.navigation.SimulationOptions;importcom.google.android.libraries.navigation.SupportNavigationFragment;importcom.google.android.libraries.navigation.TimeAndDistance;importcom.google.android.libraries.navigation.Waypoint;importjava.util.ArrayList;importjava.util.List;/***AnactivitythatdisplaysamapandanavigationUI,guidingtheuserfromtheircurrentlocation*tomultipledestinations,alsoknownaswaypoints.*/publicclassNavigationActivityMultiDestinationextendsAppCompatActivity{privatestaticfinalStringTAG=NavigationActivityMultiDestination.class.getSimpleName();privatestaticfinalStringDISPLAY_BOTH="both";privatestaticfinalStringDISPLAY_TOAST="toast";privatestaticfinalStringDISPLAY_LOG="log";privateNavigatormNavigator;privateRoadSnappedLocationProvidermRoadSnappedLocationProvider;privateSupportNavigationFragmentmNavFragment;privatefinalList<Waypoint>mWaypoints=newArrayList<>();privateNavigator.ArrivalListenermArrivalListener;privateNavigator.RouteChangedListenermRouteChangedListener;privateNavigator.RemainingTimeOrDistanceChangedListenermRemainingTimeOrDistanceChangedListener;privateRoadSnappedLocationProvider.LocationListenermLocationListener;privateBundlemSavedInstanceState;privatestaticfinalStringKEY_JOURNEY_IN_PROGRESS="journey_in_progress";privatebooleanmJourneyInProgress=false;//Setfieldsforrequestinglocationpermission.privatestaticfinalintPERMISSIONS_REQUEST_ACCESS_FINE_LOCATION=1;privatebooleanmLocationPermissionGranted;/***Setsupthenavigatorwhentheactivityiscreated.**@paramsavedInstanceStateTheactivitystatebundle.*/@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);//Savethenavigatorstate,usedtodeterminewhetherajourneyisinprogress.mSavedInstanceState=savedInstanceState;if(mSavedInstanceState!=null && mSavedInstanceState.containsKey(KEY_JOURNEY_IN_PROGRESS)){mJourneyInProgress=(mSavedInstanceState.getInt(KEY_JOURNEY_IN_PROGRESS)!=0);}setContentView(R.layout.activity_main);//InitializetheNavigationSDK.initializeNavigationSdk();}/**Releasesnavigationlistenerswhentheactivityisdestroyed.*/@OverrideprotectedvoidonDestroy(){super.onDestroy();if((mJourneyInProgress) && (this.isFinishing())){mNavigator.removeArrivalListener(mArrivalListener);mNavigator.removeRouteChangedListener(mRouteChangedListener);mNavigator.removeRemainingTimeOrDistanceChangedListener(mRemainingTimeOrDistanceChangedListener);if(mRoadSnappedLocationProvider!=null){mRoadSnappedLocationProvider.removeLocationListener(mLocationListener);}displayMessage("OnDestroy: Released navigation listeners.",DISPLAY_LOG);}}/**Savesthestateoftheappwhentheactivityispaused.*/@OverrideprotectedvoidonSaveInstanceState(BundleoutState){super.onSaveInstanceState(outState);if(mJourneyInProgress){outState.putInt(KEY_JOURNEY_IN_PROGRESS,1);}else{outState.putInt(KEY_JOURNEY_IN_PROGRESS,0);}}/***StartstheNavigationSDKandsetsthecameratofollowthedevice's location. Calls the*navigateToPlaces()methodwhenthenavigatorisready.*/privatevoidinitializeNavigationSdk(){/**Requestlocationpermission,sothatwecangetthelocationofthe*device.Theresultofthepermissionrequestishandledbyacallback,*onRequestPermissionsResult.*/if(ContextCompat.checkSelfPermission(this.getApplicationContext(),android.Manifest.permission.ACCESS_FINE_LOCATION)==PackageManager.PERMISSION_GRANTED){mLocationPermissionGranted=true;}else{ActivityCompat.requestPermissions(this,newString[]{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;}//Getanavigator.NavigationApi.getNavigator(this,newNavigationApi.NavigatorListener(){/**SetsupthenavigationUIwhenthenavigatorisreadyforuse.*/@OverridepublicvoidonNavigatorReady(Navigatornavigator){displayMessage("Navigator ready.",DISPLAY_BOTH);mNavigator=navigator;mNavFragment=(SupportNavigationFragment)getSupportFragmentManager().findFragmentById(R.id.navigation_fragment);//Setthecameratofollowthedevicelocationwith'TILTED'drivingview.mNavFragment.getMapAsync(googleMap-> googleMap.followMyLocation(CameraPerspective.TILTED));//Navigatetothespecifiedplaces.navigateToPlaces();}/***HandleserrorsfromtheNavigationSDK.**@paramerrorCodeTheerrorcodereturnedbythenavigator.*/@OverridepublicvoidonError(@NavigationApi.ErrorCodeinterrorCode){switch(errorCode){caseNavigationApi.ErrorCode.NOT_AUTHORIZED:displayMessage("Error loading Navigation SDK: Your API key is "+"invalid or not authorized to use the Navigation SDK.",DISPLAY_BOTH);break;caseNavigationApi.ErrorCode.TERMS_NOT_ACCEPTED:displayMessage("Error loading Navigation SDK: User did not accept "+"the Navigation Terms of Use.",DISPLAY_BOTH);break;caseNavigationApi.ErrorCode.NETWORK_ERROR:displayMessage("Error loading Navigation SDK: Network error.",DISPLAY_BOTH);break;caseNavigationApi.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);}}});}/**Requestsdirectionsfromtheuser's current location to a list of waypoints. */privatevoidnavigateToPlaces(){//Setupawaypointforeachplacethatwewanttogoto.createWaypoint("ChIJq6qq6jauEmsRJAf7FjrKnXI","Sydney Star");createWaypoint("ChIJ3S-JXmauEmsRUcIaWtf4MzE","Sydney Opera House");createWaypoint("ChIJLwgLFGmuEmsRzpDhHQuyyoU","Sydney Conservatorium of Music");//Ifthisjourneyisalreadyinprogress,noneedtorestartnavigation.//Thiscanhappenwhentheuserrotatesthedevice,orsendstheapptothebackground.if(mSavedInstanceState!=null
&& mSavedInstanceState.containsKey(KEY_JOURNEY_IN_PROGRESS)
&& mSavedInstanceState.getInt(KEY_JOURNEY_IN_PROGRESS)==1){return;}//Createafuturetoawaittheresultoftheasynchronousnavigatortask.ListenableResultFuture<Navigator.RouteStatus> pendingRoute=mNavigator.setDestinations(mWaypoints);//DefinetheactiontoperformwhentheSDKhasdeterminedtheroute.pendingRoute.setOnResultListener(newListenableResultFuture.OnResultListener<Navigator.RouteStatus>(){@OverridepublicvoidonResult(Navigator.RouteStatuscode){switch(code){caseOK:mJourneyInProgress=true;//HidethetoolbartomaximizethenavigationUI.if(getActionBar()!=null){getActionBar().hide();}//Registersomelistenersfornavigationevents.registerNavigationListeners();//Displaythetimeanddistancetoeachwaypoint.displayTimesAndDistances();//Enablevoiceaudioguidance(throughthedevicespeaker).mNavigator.setAudioGuidance(Navigator.AudioGuidance.VOICE_ALERTS_AND_GUIDANCE);//Simulatevehicleprogressalongtheroutefordemo/debugbuilds.if(BuildConfig.DEBUG){mNavigator.getSimulator().simulateLocationsAlongExistingRoute(newSimulationOptions().speedMultiplier(5));}//Startturn-by-turnguidancealongthecurrentroute.mNavigator.startGuidance();break;//Handleerrorconditionsreturnedbythenavigator.caseNO_ROUTE_FOUND:displayMessage("Error starting navigation: No route found.",DISPLAY_BOTH);break;caseNETWORK_ERROR:displayMessage("Error starting navigation: Network error.",DISPLAY_BOTH);break;caseROUTE_CANCELED:displayMessage("Error starting navigation: Route canceled.",DISPLAY_BOTH);break;default:displayMessage("Error starting navigation: "+String.valueOf(code),DISPLAY_BOTH);}}});}/***CreatesawaypointfromagivenplaceIDandtitle.**@paramplaceIdTheIDoftheplacetobeconvertedtoawaypoint.*@paramtitleAdescriptivetitleforthewaypoint.*/privatevoidcreateWaypoint(StringplaceId,Stringtitle){try{mWaypoints.add(Waypoint.builder().setPlaceIdString(placeId).setTitle(title).build());}catch(Waypoint.UnsupportedPlaceIdExceptione){displayMessage("Error starting navigation: Place ID is not supported: "+placeId,DISPLAY_BOTH);}}/**Displaysthecalculatedtraveltimeanddistancetoeachwaypoint.*/privatevoiddisplayTimesAndDistances(){List<TimeAndDistance>timesAndDistances=mNavigator.getTimeAndDistanceList();intleg=1;Stringmessage="You're on your way!";for(TimeAndDistancetimeAndDistance:timesAndDistances){message=message+"\nRoute leg: "+leg+++": Travel time (seconds): "+timeAndDistance.getSeconds()+". Distance (meters): "+timeAndDistance.getMeters();}displayMessage(message,DISPLAY_BOTH);}/***Registerssomeeventlistenerstoshowamessageandtakeothernecessarystepswhenspecific*navigationeventsoccur.*/privatevoidregisterNavigationListeners(){mArrivalListener=newNavigator.ArrivalListener(){@OverridepublicvoidonArrival(ArrivalEventarrivalEvent){displayMessage("onArrival: You've arrived at a waypoint: "+mNavigator.getCurrentRouteSegment().getDestinationWaypoint().getTitle(),DISPLAY_BOTH);//Startturn-by-turnguidanceforthenextlegoftheroute.if(arrivalEvent.isFinalDestination()){displayMessage("onArrival: You've arrived at the final destination.",DISPLAY_BOTH);}else{mNavigator.continueToNextDestination();mNavigator.startGuidance();}}};//Listensforarrivalatawaypoint.mNavigator.addArrivalListener(mArrivalListener);mRouteChangedListener=newNavigator.RouteChangedListener(){@OverridepublicvoidonRouteChanged(){displayMessage("onRouteChanged: The driver's route has changed. Current waypoint: "+mNavigator.getCurrentRouteSegment().getDestinationWaypoint().getTitle(),DISPLAY_LOG);}};//Listensforchangesintheroute.mNavigator.addRouteChangedListener(mRouteChangedListener);//Listensforroad-snappedlocationupdates.mRoadSnappedLocationProvider=NavigationApi.getRoadSnappedLocationProvider(getApplication());mLocationListener=newRoadSnappedLocationProvider.LocationListener(){@OverridepublicvoidonLocationChanged(Locationlocation){displayMessage("onLocationUpdated: Navigation engine has provided a new"+" road-snapped location: "+location.toString(),DISPLAY_LOG);}@OverridepublicvoidonRawLocationUpdate(Locationlocation){displayMessage("onLocationUpdated: Navigation engine has provided a new"+" raw location: "+location.toString(),DISPLAY_LOG);}};if(mRoadSnappedLocationProvider!=null){mRoadSnappedLocationProvider.addLocationListener(mLocationListener);}else{displayMessage("ERROR: Failed to get a location provider",DISPLAY_LOG);}mRemainingTimeOrDistanceChangedListener=newNavigator.RemainingTimeOrDistanceChangedListener(){@OverridepublicvoidonRemainingTimeOrDistanceChanged(){displayMessage("onRemainingTimeOrDistanceChanged: Time or distance estimate"+" has changed.",DISPLAY_LOG);}};//Listensforchangesintimeordistance.mNavigator.addRemainingTimeOrDistanceChangedListener(60,100,mRemainingTimeOrDistanceChangedListener);}/**Handlestheresultoftherequestforlocationpermissions.*/@OverridepublicvoidonRequestPermissionsResult(intrequestCode,@NonNullString[]permissions,@NonNullint[]grantResults){mLocationPermissionGranted=false;switch(requestCode){casePERMISSIONS_REQUEST_ACCESS_FINE_LOCATION:{//Ifrequestiscanceled,theresultarraysareempty.if(grantResults.length > 0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){mLocationPermissionGranted=true;}}}}/***Showsamessageonscreenandinthelog.Usedwhensomethinggoeswrong.**@paramerrorMessageThemessagetodisplay.*/privatevoiddisplayMessage(StringerrorMessage,StringdisplayMedium){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);}}}
Wykrywanie przybycia do miejsca docelowego
Miejsce docelowe to miejsce docelowe lub punkt pośredni. Aby wykryć przybycie, wywołaj funkcję Navigator.addArrivalListener(), która rejestruje wywołanie zwrotne, gdy urządzenie dotrze do miejsca docelowego.
Po dotarciu na miejsce pakiet Navigation SDK na Androida wywołuje funkcję zwrotną
onArrival(), której można użyć do zatrzymania
wskazówek dojazdu krok po kroku za pomocą funkcji Navigator.stopGuidance() lub do przejścia do następnego punktu trasy za pomocą funkcji
Navigator.continueToNextDestination(). Jeśli sesja nawigacji obejmowała tylko 1 miejsce docelowe lub jeśli na liście nie ma już żadnych miejsc docelowych, wywołanie funkcji Navigator.continueToNextDestination()
automatycznie zatrzymuje wskazówki.
Gdy zadzwonisz pod numer continueToNextDestination(), nawigator odrzuci wszystkie informacje o poprzednim miejscu docelowym. Jeśli chcesz przeanalizować informacje o poprzednim odcinku trasy, musisz pobrać je z nawigatora przed wywołaniem funkcji continueToNextDestination().
Aby uniknąć wycieków pamięci, musisz wywołać metodę
removeArrivalListener(listener), gdy nie będziesz już potrzebować odbiornika.
mNavigator.addArrivalListener(newNavigator.ArrivalListener(){@OverridepublicvoidonArrival(ArrivalEventarrivalEvent){displayMessage("onArrival: You've arrived at a waypoint: "+mNavigator.getCurrentRouteSegment().getDestinationWaypoint().getTitle(),DISPLAY_BOTH);// Start turn-by-turn guidance for the next leg of the route.if(arrivalEvent.isFinalDestination()){displayMessage("onArrival: You've arrived at the final destination.",DISPLAY_BOTH);}else{mNavigator.continueToNextDestination();mNavigator.startGuidance();}}});
Otrzymywanie aktualizacji lokalizacji
Uzyskaj RoadSnappedLocationProvider z NavigationApi, a następnie zadzwoń pod numer RoadSnappedLocationProvider.addLocationListener(), aby zarejestrować się w celu otrzymywania oddzwonienia, gdy zmieni się lokalizacja lub kierunek urządzenia. Pamiętaj, że ta lokalizacja jest przyciągana do drogi, więc może się różnić od lokalizacji zwracanej przez dostawcę lokalizacji łączonej w interfejsach API lokalizacji Usług Google Play.
Pakiet SDK do nawigacji udostępnia aktualizacje lokalizacji tak często, jak to możliwe. Gdy dostępna jest aktualizacja lokalizacji, pakiet Navigation SDK wywołuje funkcję zwrotną onLocationChanged().
Aktualizacje lokalizacji przyciągane do drogi są niezależne od nawigacji i mogą być kontynuowane nawet po jej zatrzymaniu. Subskrypcja aktualizacji lokalizacji może powodować szybsze wyczerpywanie się baterii, wyciek pamięci lub niezamierzone zbieranie danych o lokalizacji urządzenia, jeśli pozostawisz aktualizacje lokalizacji działające w tle. Wywołaj
RoadSnappedLocationProvider.removeLocationListener
gdy nie potrzebujesz już odbiornika.
mRoadSnappedLocationProvider=NavigationApi.getRoadSnappedLocationProvider(getApplication());if(mRoadSnappedLocationProvider!=null){mRoadSnappedLocationProvider.addLocationListener(newRoadSnappedLocationProvider.LocationListener(){@OverridepublicvoidonLocationChanged(Locationlocation){displayMessage("onLocationUpdated: Navigation engine has provided a new"+" road-snapped location: "+location.toString(),DISPLAY_LOG);}});}else{displayMessage("ERROR: Failed to get a location provider",DISPLAY_LOG);}
Otrzymywanie aktualizacji czasu i odległości
Wywołaj funkcję
Navigator.addRemainingTimeOrDistanceChangedListener()
aby zarejestrować się w celu otrzymania połączenia zwrotnego, gdy pozostały czas (w sekundach) lub odległość (w metrach) zmieni się o wartość większą niż podany próg.
Gdy zmiana czasu lub odległości przekroczy określoną wartość, pakiet Navigation SDK wywoła funkcję zwrotną onRemainingTimeOrDistanceChanged().
Aby sprawdzić pozostały czas i odległość, zadzwoń pod numer Navigator.getTimeAndDistanceList(). Pamiętaj, że czasy i odległości na liście są skumulowane: pokazują czas i odległość od bieżącej lokalizacji do każdego punktu pośredniego, a nie od jednego punktu pośredniego do drugiego.
Obiekt TimeAndDistance zwraca teraz też delaySeverity. Ten wyliczenie będzie miało wartość heavy, medium, light lub unknown. Odpowiada to kolorowi, który widzisz w interfejsie Map Google (duże natężenie = czerwony, średnie = żółty, małe = zielony). Jest to przydatne, jeśli chcesz utworzyć własny stopkę z szacowanym czasem dotarcia.
W przykładzie poniżej żądanie oddzwonienia jest wysyłane, jeśli pozostały czas zmieni się o ponad 60 sekund lub pozostała odległość zmieni się o ponad 100 metrów.
mNavigator.addRemainingTimeOrDistanceChangedListener(60,100,newNavigator.RemainingTimeOrDistanceChangedListener(){@OverridepublicvoidonRemainingTimeOrDistanceChanged(){displayMessage("onRemainingTimeOrDistanceChanged: Time or distance estimate"+" has changed.",DISPLAY_LOG);}});
Możesz wyświetlać informacje o pozostałym czasie i dystansie na wbudowanym wyświetlaczu, korzystając z metody setEtaCardEnabled() i przekazując parametr o wartości TRUE. Aby wyłączyć wyświetlanie czasu i odległości, ustaw tę wartość na FALSE.
Możesz też udostępnić szacowany czas dotarcia do wielu punktów pośrednich za pomocą metody
getTimeAndDistanceList().
Otrzymywanie aktualizacji trasy
Zadzwoń pod numer Navigator.addRouteChangedListener(), aby zarejestrować się w celu otrzymywania połączeń zwrotnych, gdy trasa ulegnie zmianie.
mNavigator.addRouteChangedListener(newNavigator.RouteChangedListener(){@OverridepublicvoidonRouteChanged(){displayMessage("onRouteChanged: The driver's route has changed. Current waypoint: "+mNavigator.getCurrentRouteSegment().getDestinationWaypoint().getTitle(),DISPLAY_LOG);}});
Poniższy przykład pokazuje nasłuchiwanie zmian trybu nocnego w fragmencie nawigacji.
mNavFragment.addOnNightModeChangedListener(newNavigationView.OnNightModeChangedListener(){@OverridepublicvoidonNightModeChanged(NightModeChangedEventnightModeChangedEvent){displayMessage("Night mode is active: "+nightModeChangedEvent.inNightMode(),DISPLAY_LOG);}});
Tryb nocny możesz też ustawić automatycznie. Więcej informacji znajdziesz w artykule Ustawianie trybu nocnego.
[[["Łatwo zrozumieć","easyToUnderstand","thumb-up"],["Rozwiązało to mój problem","solvedMyProblem","thumb-up"],["Inne","otherUp","thumb-up"]],[["Brak potrzebnych mi informacji","missingTheInformationINeed","thumb-down"],["Zbyt skomplikowane / zbyt wiele czynności do wykonania","tooComplicatedTooManySteps","thumb-down"],["Nieaktualne treści","outOfDate","thumb-down"],["Problem z tłumaczeniem","translationIssue","thumb-down"],["Problem z przykładami/kodem","samplesCodeIssue","thumb-down"],["Inne","otherDown","thumb-down"]],["Ostatnia aktualizacja: 2025-07-26 UTC."],[[["The Navigation SDK for Android allows you to listen for events like arrival at destinations, location updates, and changes in time or distance during navigation."],["You can register callbacks to detect arrival at waypoints or the final destination and trigger actions like resuming or stopping navigation."],["Utilize listeners to receive road-snapped location updates, remaining time/distance changes, and route updates, ensuring proper resource management to prevent memory leaks."],["The SDK provides methods for accessing route information, handling ETA visualization, and responding to night mode changes for a comprehensive navigation experience."],["Remember to remove listeners when they are no longer needed to avoid memory leaks and optimize resource utilization."]]],[]]