gawron103
gawron103

Reputation: 309

Proper usage of Google API (Navigation) in Android clean architecture

I have a question regarding usage of Google APIs (in my case NavigationAPI) in clean architecture.

So in order to use google navigation it is necessary to have Navigator object from NavigationApi.getNavigator API. Initially I thought that it’s ok to put all necessary implementation in DATA layer, however this layer is supposed to only hold and provide access to data (local, remote). But then Navigator is highly dependent on SupportNavigationFragment which is in presentation layer. As we know, lower layers shouldn’t depend on higher layers.

So next I thought that all mentioned implementation should be moved to fragment, but I am not 100% sure if this is correct even if it sounds reasonable. Does anyone have any experience with google api in clean arch?

Functionality that I need:


private var navigator: Navigator? = null

override fun initializeNavigator(activity: FragmentActivity) {
    NavigationApi.getNavigator(activity, object : NavigationApi.NavigatorListener {
        override fun onNavigatorReady(navigator: Navigator?) {
            navigator = navigator
            addListeners()
        }

        override fun onError(errorCode: Int) {
            handleError(errorCode)
        }
    })
}

override fun startNavigation() {
    navigator?.setAudioGuidance(Navigator.AudioGuidance.VOICE_ALERTS_AND_GUIDANCE)
    navigator?.startGuidance()
}

override fun stopNavigation() {
    navigator?.stopGuidance()
    navigator?.clearDestinations()
}


override fun getRouteSummary(waypoint: Waypoint, options: RoutingOptions) = callbackFlow {
    navigator?.let { navigator ->
        val pendingRoute = navigator.setDestination(waypoint, options)
        pendingRoute.setOnResultListener { code ->
            _navigationStateFlow.value = NavigationState.SUMMARY
            val result = trySend(
                NavigationSummary(
                    response = code,
                    meters = navigator.currentTimeAndDistance.meters,
                    seconds = navigator.currentTimeAndDistance.seconds
                )
            )
        }

        awaitClose {
        …
        }
    }
}

private fun addListeners() {
    val arrivalListener = Navigator.ArrivalListener {
        navigator?.clearDestinations()
    }
    navigator?.addArrivalListener(arrivalListener)

    val routeChangedListener = Navigator.RouteChangedListener {
        …
    }
    navigator?.addRouteChangedListener(routeChangedListener)
}

private fun handleError(errorCode: Int) {
    when (errorCode) {
        NavigationApi.ErrorCode.NOT_AUTHORIZED -> {
            …
        }

        NavigationApi.ErrorCode.TERMS_NOT_ACCEPTED -> {
            ...
        }

        NavigationApi.ErrorCode.NETWORK_ERROR -> {
            …
        }

        NavigationApi.ErrorCode.LOCATION_PERMISSION_MISSING -> {
            …
        }

        else -> {
            ...
        }
    }
}

Upvotes: 1

Views: 58

Answers (1)

CommonsWare
CommonsWare

Reputation: 1007369

Quoting the docs:

Note that Navigator is a singleton; if you call this method multiple times, each call will return the same Navigator.

As a result, IMHO, there is no reason to have the Navigator be part of the UI layer. I would have my own singleton manager that wraps the Navigator to bridge between the Navigator API and the internal needs of my app. I would have that manager implement an interface describing its API, so I can create test fakes for it.

In terms of your specific concerns:

initialization of navigator needs activity as parameter (there is also possibility to pass application instead, didn’t check that yet)

Off the cuff, I would use the Application approach.

setting the destination (via navigator.setDestination(waypoint, options)) has the effect of drawing a path on the map

The result of a Web service call has the effect of updating your UI. This does not mean that you make the Web service call directly from the UI layer. Similarly, the fact that Navigator triggers UI updates does not mean that the Navigator should be part of the UI layer.

Upvotes: 0

Related Questions