mapbox 导航记录(release-v2.15分支 纯kotlin)

一、简单使用示例

1. 初始化 MapboxNavigation

初始化时使用 NavigationOptions 设置一些参数,包括accessToken、appMetaData、LocationEngine等,其它还有很多,具体可以详看 NavigationOptions 类的内部。

下面示例中 LocationEngine 使用的重演定位引擎,可以看到模拟导航的效果,关键的两个类就是 ReplayLocationEngine 和 MapboxReplayer 。

/* ----- Mapbox Navigation components ----- */
private lateinit var mapboxNavigation: MapboxNavigation

private val mapboxReplayer = MapboxReplayer()

// initialize Mapbox Navigation
mapboxNavigation = MapboxNavigationProvider.create(
    NavigationOptions.Builder(applicationContext)
        .accessToken(getMapboxAccessTokenFromResources())
        .eventsAppMetadata(
            EventsAppMetadata.Builder(
                    BuildConfig.APPLICATION_ID,
                    BuildConfig.VERSION_NAME
                ).build()
            )
        .locationEngine(ReplayLocationEngine(mapboxReplayer))
        .build()
)

2. 初始化 LocationObserver,对位置改变做观察

navigationLocationProvider 只是把当前导航的位置点给到 MapView,实现地图移动或者加位置图标等。

MapboxNavigationViewportDataSource 也是一样,移动地图的Camera到一个合适的位置,要结合 NavigationCamera 使用。NavigationCamera 还可以改变导航是 Following 还是 Overview 。

// camera
private lateinit var navigationCamera: NavigationCamera
private lateinit var viewportDataSource: MapboxNavigationViewportDataSource

// initialize Navigation Camera
viewportDataSource = MapboxNavigationViewportDataSource(
    binding.mapView.getMapboxMap()
)
navigationCamera = NavigationCamera(
    binding.mapView.getMapboxMap(),
    binding.mapView.camera,
    viewportDataSource
)

/* ----- Location and route progress callbacks ----- */
private val locationObserver = object : LocationObserver {
    override fun onNewRawLocation(rawLocation: Location) {
        // not handled
    }

    override fun onNewLocationMatcherResult(locationMatcherResult: LocationMatcherResult) {
        // update location puck's position on the map
        navigationLocationProvider.changePosition(
            location = locationMatcherResult.enhancedLocation,
            keyPoints = locationMatcherResult.keyPoints,
        )

        // update camera position to account for new location
        viewportDataSource.onLocationChanged(locationMatcherResult.enhancedLocation)
        viewportDataSource.evaluate()
    }
}

3. 初始化 RoutesObserver,对多条路线的处理

private val routesObserver = RoutesObserver { result ->
        if (result.routes.isNotEmpty()) {
            // generate route geometries asynchronously and render them
            CoroutineScope(Dispatchers.Main).launch {
                val result = routeLineAPI.setRoutes(
                    listOf(RouteLine(result.routes.first(), null))
                )
                val style = mapboxMap.getStyle()
                if (style != null) {
                    routeLineView.renderRouteDrawData(style, result)
                }
            }

            // update the camera position to account for the new route
            viewportDataSource.onRouteChanged(result.routes.first())
            viewportDataSource.evaluate()
        } else {
            // remove the route line and route arrow from the map
            val style = mapboxMap.getStyle()
            if (style != null) {
                routeLineAPI.clearRouteLine { value ->
                    routeLineView.renderClearRouteLineValue(
                        style,
                        value
                    )
                }
                routeArrowView.render(style, routeArrowAPI.clearArrows())
            }

            // remove the route reference to change camera position
            viewportDataSource.clearRouteData()
            viewportDataSource.evaluate()
        }
}

4. 初始化 NavigationSessionStateObserver ,对导航状态的监测

private val navigationSessionStateObserver = NavigationSessionStateObserver {
    logD("NavigationSessionState=$it", LOG_CATEGORY)
    logD("sessionId=${mapboxNavigation.getNavigationSessionState().sessionId}", LOG_CATEGORY)
}

5. 初始化 RouteProgressObserver ,对导航进度的监测

最关键的部分,如下是正常导航时的进度处理。但是对于模拟导航,只需要实例化 ReplayProgressObserver 对象。

// 模拟导航使用
private val routeProgressObserver1 = ReplayProgressObserver(mapboxReplayer)

// 正常导航使用
    private val routeProgressObserver =
        RouteProgressObserver { routeProgress ->
            // update the camera position to account for the progressed fragment of the route
            viewportDataSource.onRouteProgressChanged(routeProgress)
            viewportDataSource.evaluate()

            // show arrow on the route line with the next maneuver
            val maneuverArrowResult = routeArrowAPI.addUpcomingManeuverArrow(routeProgress)
            val style = mapboxMap.getStyle()
            if (style != null) {
                routeArrowView.renderManeuverUpdate(style, maneuverArrowResult)
            }

            // update top maneuver instructions
            val maneuvers = maneuverApi.getManeuvers(routeProgress)
            maneuvers.fold(
                { error ->
                    Toast.makeText(
                        this@MapboxNavigationActivity,
                        error.errorMessage,
                        Toast.LENGTH_SHORT
                    ).show()
                },
                {
                    binding.maneuverView.visibility = VISIBLE
                    binding.maneuverView.renderManeuvers(maneuvers)
                }
            )

            // update bottom trip progress summary
            binding.tripProgressView.render(tripProgressApi.getTripProgress(routeProgress))
        }

6. 初始化 VoiceInstructionsObserver ,对语音指令的监测

// 语音播报对象
private lateinit var voiceInstructionsPlayer: MapboxVoiceInstructionsPlayer

voiceInstructionsPlayer = MapboxVoiceInstructionsPlayer(
    this,
    Locale.US.language
)

// 静音和取消静音
voiceInstructionsPlayer.volume(SpeechVolume(0f))
voiceInstructionsPlayer.volume(SpeechVolume(1f))

/* ----- Voice instruction callbacks ----- */
private val voiceInstructionsObserver =
    VoiceInstructionsObserver { voiceInstructions ->
        speechAPI.generate(
            voiceInstructions,
            speechCallback
        )
    }

// speechCallback 中做 play
private val speechCallback =
        MapboxNavigationConsumer<Expected<SpeechError, SpeechValue>> { expected ->
            expected.fold(
                { error ->
                    // play the instruction via fallback text-to-speech engine
                    voiceInstructionsPlayer.play(
                        error.fallback,
                        voiceInstructionsPlayerCallback
                    )
                },
                { value ->
                    // play the sound file from the external generator
                    voiceInstructionsPlayer.play(
                        value.announcement,
                        voiceInstructionsPlayerCallback
                    )
                }
            )
        }

7. findRoute并将路线设置给导航模块,然后开启导航

// findRoute
mapboxNavigation.requestRoutes()

// 路线获取成功 onRoutesReady 后的处理
private fun setRouteAndStartNavigation(route: List<NavigationRoute>) {
    // set route
    mapboxNavigation.setNavigationRoutes(route)

    // show UI elements
    binding.soundButton.visibility = VISIBLE
    binding.routeOverview.visibility = VISIBLE
    binding.tripProgressCard.visibility = VISIBLE
    binding.routeOverview.showTextAndExtend(2000L)
    binding.soundButton.unmuteAndExtend(2000L)

    // move the camera to overview when new route is available
    navigationCamera.requestNavigationCameraToOverview()
}

override fun onStart() {
    super.onStart()
    mapboxNavigation.registerRoutesObserver(routesObserver)
    mapboxNavigation.registerNavigationSessionStateObserver(navigationSessionStateObserver)
//    mapboxNavigation.registerRouteProgressObserver(routeProgressObserver)
    mapboxNavigation.registerRouteProgressObserver(routeProgressObserver1)
    mapboxNavigation.registerLocationObserver(locationObserver)
    mapboxNavigation.registerVoiceInstructionsObserver(voiceInstructionsObserver)

    // 实际导航只需要注册好上面的观察者,下面时模拟导航的特殊开启方式
    mapboxReplayer.pushRealLocation(this, 0.0)
    mapboxReplayer.playbackSpeed(1.5)
    mapboxReplayer.play()
}

二、关键类

类名 所属模块 作用
MapboxNavigation libnavigation-core 核心类,要给它配置token,定位引擎等。
mapboxNavigation.startTripSession()
registerLocationObserver() 观察位置变化。
registerRoutesObserver() 对导航路线的处理,比如渲染,箭头等。
registerNavigationSessionStateObserver()
registerRouteProgressObserver() 导航进度。
registerVoiceInstructionsObserver() 语音指令。
NavigationOptions libnavigation-base 给 MapboxNavigation 配置token,定位引擎等使用此对象。
还有很多其它的配置项。
RoutesObserver libnavigation-core 对导航路线改变时,在这个接口方法中实现渲染。
RouteProgressObserver libnavigation-core 提供状态、进度和其他有关当前逐点路由的信息的回调。
LocationObserver libnavigation-core 监听位置更新。
VoiceInstructionsObserver libnavigation-core 语音指令接口。
----------------------------- ----------------------------- -----------------------------
MapboxNavigationViewportDataSource libnavui-maps UI相关,需要把 MapView 对象传递给此类。
NavigationCamera libnavui-maps UI相关,需要把 MapView,camera,MapboxNavigationViewportDataSource 对象传递给此类。
NavigationBasicGesturesHandler libnavui-maps UI相关,基础手势。
MapboxManeuverApi libnavui-maneuver UI相关,顶部显示还有多少米向左向右转等信息。
MapboxTripProgressApi libnavui-tripprogress UI相关,底部进度,剩余时间,剩余距离,当前时间。
MapboxSpeechApi libnavui-voice UI相关,语音部分。
MapboxVoiceInstructionsPlayer libnavui-voice UI相关,语音部分。
MapboxRouteLineApi libnavui-maps UI相关,路线上图相关。
MapboxRouteLineView libnavui-maps UI相关,路线上图相关。
MapboxRouteArrowView libnavui-maps UI相关,路线上图相关。
----------------------------- ----------------------------- -----------------------------
ReplayLocationEngine libnavigation-core 模拟导航相关类,要在NavigationOptions设置这种定位引擎
MapboxReplayer libnavigation-core 模拟导航相关类,控制模拟导航play,finish等
ReplayRouteMapper libnavigation-core 模拟导航相关类,利用它里面的方法把要模拟的路线对象DirectionsRoute设置进去
ReplayProgressObserver libnavigation-core 模拟导航相关类,观察模拟导航的进度,替代正常导航进度观察RouteProgressObserver

三、NavigationView

布局文件 mapbox_navigation_view_layout.xml

init { } 方法块中会创建MapView并添加到布局,利用mapLayoutCoordinator(binding) 实例化 MapLayoutCoordinator

再利用 MapLayoutCoordinator 里的方法给 core 模块中的 MapboxNavigation 绑定 MapView。

MapView 的创建使用 MapViewBinder,而对它设置样式使用 MapStyleLoader

NavigationViewContext
NavigationViewBinder
NavigationViewStyles
NavigationViewOptions
MapViewOwner
MapStyleLoader
_mapViewBinder
_infoPanelRoutePreviewButtonBinder
_infoPanelStartNavigationButtonBinder
_infoPanelEndNavigationButtonBinder
_infoPanelContentBinder

四、获取导航路线 requestRoutes() 详细

MapboxNavigation 中获取导航路线的方法,有两个方法,参数有差异

fun requestRoutes(
    routeOptions: RouteOptions,
    routesRequestCallback: RouterCallback
)

fun requestRoutes(
    routeOptions: RouteOptions,
    callback: NavigationRouterCallback
)

RouterCallback 中获取导航路线成功得到的是 DirectionsRoute 集合,在模拟导航中使用 DirectionsRoute 对象。也对应结合 MapboxNavigation.setRoutes(List) 使用,方法内部会利用 toNavigationRoutes() 做转换。

NavigationRouterCallback 中获取导航路线成功得到的是 NavigationRoute 集合,对应结合 MapboxNavigation.setNavigationRoutes(List) 使用。

toNavigationRoutes() 是把 DirectionsRoute 集合转为 NavigationRoute 集合,也有 toDirectionsRoutes() 可以把 NavigationRoute 集合转为 DirectionsRoute 集合。

你可能感兴趣的:(mapbox地图,android,kotlin)