您的应用可以监听用户沿着路线导航时发生的事件。
概览
使用以下接口监听导航事件:
查看代码
显示/隐藏 Java 代码
。
package com.example.navsdkmultidestination;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import com.google.android.libraries.navigation.ArrivalEvent;
import com.google.android.libraries.navigation.Camera;
import com.google.android.libraries.navigation.ListenableResultFuture;
import com.google.android.libraries.navigation.LocationEvent;
import com.google.android.libraries.navigation.NavigationApi;
import com.google.android.libraries.navigation.Navigator;
import com.google.android.libraries.navigation.RoadSnappedLocationProvider;
import com.google.android.libraries.navigation.SimulationOptions;
import com.google.android.libraries.navigation.SupportNavigationFragment;
import com.google.android.libraries.navigation.TimeAndDistance;
import com.google.android.libraries.navigation.Waypoint;
import java.util.ArrayList;
import java.util.List;
/**
* An activity that displays a map and a navigation UI, guiding the user
* from their current location to multiple destinations, also known as waypoints.
*/
public class NavigationActivityMultiDestination extends AppCompatActivity {
private static final String TAG = NavigationActivityMultiDestination.class.getSimpleName();
private static final String DISPLAY_BOTH = "both";
private static final String DISPLAY_TOAST = "toast";
private static final String DISPLAY_LOG = "log";
private Navigator mNavigator;
private RoadSnappedLocationProvider mRoadSnappedLocationProvider;
private SupportNavigationFragment mNavFragment;
private final List<Waypoint> mWaypoints = new ArrayList<>();
private Navigator.ArrivalListener mArrivalListener;
private Navigator.RouteChangedListener mRouteChangedListener;
private Navigator.RemainingTimeOrDistanceChangedListener
mRemainingTimeOrDistanceChangedListener;
private RoadSnappedLocationProvider.LocationListener mLocationListener;
private Bundle mSavedInstanceState;
private static final String KEY_JOURNEY_IN_PROGRESS = "journey_in_progress";
private boolean mJourneyInProgress = false;
// Set fields for requesting location permission.
private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
private boolean mLocationPermissionGranted;
/**
* Sets up the navigator when the activity is created.
* @param savedInstanceState The activity state bundle.
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Save the navigator state, used to determine whether a journey is in progress.
mSavedInstanceState = savedInstanceState;
if (mSavedInstanceState != null
&& mSavedInstanceState.containsKey(KEY_JOURNEY_IN_PROGRESS)) {
mJourneyInProgress = (mSavedInstanceState.getInt(KEY_JOURNEY_IN_PROGRESS) != 0);
}
setContentView(R.layout.activity_main);
// Initialize the Navigation SDK.
initializeNavigationSdk();
}
/**
* Releases navigation listeners when the activity is destroyed.
*/
@Override
protected void onDestroy() {
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);
}
}
/**
* Saves the state of the app when the activity is paused.
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mJourneyInProgress) {
outState.putInt(KEY_JOURNEY_IN_PROGRESS, 1);
} else {
outState.putInt(KEY_JOURNEY_IN_PROGRESS, 0);
}
}
/**
* Starts the Navigation SDK and sets the camera to follow the device's location.
* Calls the navigateToPlaces() method when the navigator is ready.
*/
private void initializeNavigationSdk() {
/*
* Request location permission, so that we can get the location of the
* device. The result of the permission request is handled by a callback,
* onRequestPermissionsResult.
*/
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;
}
// Get a navigator.
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);
}
}
});
}
/**
* Requests directions from the user's current location to a list of waypoints.
*/
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);
}
}
});
}
/**
* Creates a waypoint from a given place ID and title.
* @param placeId The ID of the place to be converted to a waypoint.
* @param title A descriptive title for the 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);
}
}
/**
* Displays the calculated travel time and distance to each waypoint.
*/
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);
}
/**
* Registers some event listeners to show a message and take other necessary steps
* when specific navigation events occur.
*/
private void registerNavigationListeners() {
mArrivalListener = new Navigator.ArrivalListener() {
@Override
public void onArrival(ArrivalEvent arrivalEvent) {
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();
}
}
};
// Listens for arrival at a waypoint.
mNavigator.addArrivalListener(mArrivalListener);
mRouteChangedListener = new Navigator.RouteChangedListener() {
@Override
public void onRouteChanged() {
displayMessage("onRouteChanged: The driver's route has changed. Current waypoint: "
+ mNavigator.getCurrentRouteSegment().getDestinationWaypoint().getTitle(),
DISPLAY_LOG);
}
};
// Listens for changes in the route.
mNavigator.addRouteChangedListener(mRouteChangedListener);
// Listens for road-snapped location updates.
mRoadSnappedLocationProvider =
NavigationApi.getRoadSnappedLocationProvider(getApplication());
mLocationListener =
new RoadSnappedLocationProvider.LocationListener() {
@Override
public void onLocationChanged(LocationEvent locationEvent) {
displayMessage("onLocationUpdated: Navigation engine has provided a new"
+ " road-snapped location: "
+ locationEvent.getLocation().toString(),
DISPLAY_LOG);
}
};
if (mRoadSnappedLocationProvider != null) {
mRoadSnappedLocationProvider.addLocationListener(mLocationListener);
} else {
displayMessage("ERROR: Failed to get a location provider", DISPLAY_LOG);
}
mRemainingTimeOrDistanceChangedListener =
new Navigator.RemainingTimeOrDistanceChangedListener() {
@Override
public void onRemainingTimeOrDistanceChanged() {
displayMessage("onRemainingTimeOrDistanceChanged: Time or distance estimate"
+ " has changed.",
DISPLAY_LOG);
}
};
// Listens for changes in time or distance.
mNavigator.addRemainingTimeOrDistanceChangedListener(60, 100,
mRemainingTimeOrDistanceChangedListener);
}
/**
* Handles the result of the request for location permissions.
*/
@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;
}
}
}
}
/**
* Shows a message on screen and in the log. Used when something goes wrong.
* @param errorMessage The message to display.
*/
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);
}
}
}
检测到达目的地
在这里,目的地是指最终目的地或航点。接收者
检测到达、调用 Navigator.addArrivalListener()
、
该函数会在设备到达目的地时注册回调。
抵达后,将触发 Navigation SDK for Android
onArrival()
回调并停止精细导航。
您必须明确调用
Navigator.continueToNextDestination()
即可前进
转至下一个航点,点击 Navigator.startGuidance()
可
继续精细导航。
当您调用 continueToNextDestination()
时,导航器会舍弃所有
有关之前的目的地的信息。如果您想分析
前一个路段的相关信息,则必须检索
先从导航器中导航,然后再调用 continueToNextDestination()
。
为了避免内存泄漏,在调用 removeArrivalListener(listener)
时,
因此不再需要该监听器。
mNavigator.addArrivalListener(new Navigator.ArrivalListener() {
@Override
public void onArrival(ArrivalEvent arrivalEvent) {
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();
}
}
});
接收位置信息更新
从以下位置获取 RoadSnappedLocationProvider
:
NavigationApi
,然后调用
RoadSnappedLocationProvider.addLocationListener()
在设备的位置或方向发生变化时注册回调。
请注意,此位置与道路对应,因此可能不同于
Google Play 中的一体化位置信息提供程序返回的位置信息
服务地理位置 API。
Navigation SDK 以最高频率提供位置信息更新
当有可用的位置更新时,
Navigation SDK 会触发
onLocationChanged()
回调。
道路拦截位置更新与导航无关,
即使导航已停止,也仍会继续。订阅位置信息更新后,
导致耗电过快、内存泄漏或无意收集设备位置信息
数据。致电
RoadSnappedLocationProvider.removeLocationListener
。
mRoadSnappedLocationProvider =
NavigationApi.getRoadSnappedLocationProvider(getApplication());
if (mRoadSnappedLocationProvider != null) {
mRoadSnappedLocationProvider.addLocationListener(
new RoadSnappedLocationProvider.LocationListener() {
@Override
public void onLocationChanged(Location location) {
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);
}
接收时间和距离的最新动态
调用 Navigator.addRemainingTimeOrDistanceChangedListener()
在剩余时间(秒)或距离时注册回调
(米)的变化幅度超过指定阈值。
当时间或距离的变化幅度超过指定的量时,
Navigation SDK 会触发
onRemainingTimeOrDistanceChanged()
回调。
要查看剩余时间和距离,请调用
Navigator.getTimeAndDistanceList()
。请注意,
列表中的时间和距离是累计数据:它们显示的是
从当前位置到每个航点,而不是从一个航点到另一个航点。
TimeAndDistance
对象现在也会返回 delaySeverity
。此枚举将
为 shuffle、meduim、轻度或未知。该颜色与您
查看地图界面中的预计到达时间(深色主题 = 红色,中 = 黄色,浅色 = 绿色)。这是
如果您需要创建自己的加大型文字广告页脚,可以执行此操作。
为避免内存泄漏,您必须调用
Navigator.removeRemainingTimeOrDistanceChangedListener(listener)
。
以下示例会在剩余时间变化超过
60 秒或剩余距离变化超过 100 米。
mNavigator.addRemainingTimeOrDistanceChangedListener(60, 100,
new Navigator.RemainingTimeOrDistanceChangedListener() {
@Override
public void onRemainingTimeOrDistanceChanged() {
displayMessage("onRemainingTimeOrDistanceChanged: Time or distance estimate"
+ " has changed.",
DISPLAY_LOG);
}
});
您可以使用内置的
使用 setEtaCardEnabled()
方法显示
并传递值为 TRUE
的参数。隐藏时间/距离
请将此值设置为 FALSE
。
您也可以使用
getTimeAndDistanceList()
方法。
接收路线更新
调用 Navigator.addRouteChangedListener()
以
在路线发生变化时注册回调。
当路线发生变化时,Navigation SDK 会触发
onRouteChanged()
回调。您可以拨打
Navigator.getRouteSegments
和
Navigator.getCurrentRouteSegment()
,即可找到新的
。
为了避免内存泄漏,在调用 removeRouteChangedListener(listener)
时,
因此不再需要该监听器。
mNavigator.addRouteChangedListener(new Navigator.RouteChangedListener() {
@Override
public void onRouteChanged() {
displayMessage("onRouteChanged: The driver's route has changed. Current waypoint: "
+ mNavigator.getCurrentRouteSegment().getDestinationWaypoint().getTitle(),
DISPLAY_LOG);
}
});
检测夜间模式何时发生变化
调用 NavigationView.addOnNightModeChangedListener
或
SupportNavigationFragment.addOnNightModeChangedListener
在夜间模式发生变化时注册回调。
以下示例展示了如何在
导航 fragment。
mNavFragment.addOnNightModeChangedListener(new NavigationView.OnNightModeChangedListener() {
@Override
public void onNightModeChanged(NightModeChangedEvent nightModeChangedEvent) {
displayMessage("Night mode is active: " + nightModeChangedEvent.inNightMode(),
DISPLAY_LOG);
}
});