I'm wondering in the Clean Architecture onion diag...
# android-architecture
a
I'm wondering in the Clean Architecture onion diagram. In which layer should the navigation and tracking be in? For the navigation it seems better to belong to the presentation layer, however it could also be part of the use case layer. As it could be part of a use case description "When a user clicks on a product, if the product is a collection then head to the collections screen, otherwise head to the product details screen" I'm curious what do experts think 🤔
f
The decision is done on the use case layer, but this layer knows nothing about how it is implemented, so the navigation layer (in my opinion) may be in the last layer
s
Like Francisco said, the UseCase layer is some action/use-case that was finished with a particular result. Then a navigation/navigator in the Presenter (ViewModel) determines which screen to go to. It instructs the Framework to handle all the specific details of how to get to that screen (eg JetPack Navigation, plain Fragment, going to another Activity, etc)
a
But from what I understood from Francisco, is that the navigator will be the injected in the use case, and the implemenation will be provided from the top most layer through inversion of control, right @Francisco Javier Ruiz Rodriguez? While you're suggestion is that use case layer doesn't know anything about the navigator and the presentation layer will check the result of the usecase to handle the navigation.
So they're two different approaches.
f
Nope exactly, @Ahmed Ibrahim. I'm with Anton, the use case must response the presenter what to do, but whithout any knowledge of how it is done
i
It’s all on paper, but I think that if you are going to use AAC, you are FORCED to do navigation on the UI layer -> you can’t inject fragments/activities into the view-model even as interfaces.
And they are the only framework components that know how to navigate. It doesn’t matter if you use the new navigation component or old-style fragment transaction.
a
@Ianmedeiros I think you can get around that by using the inversion of control principle, there are solutions already for that problem, one of them is using the same approach as Cicerone using https://github.com/terrakok/Cicerone By buffering navigation commands and once the activity is ready, execute them one by one.
i
So, you will need to observe navigation events from the activity/fragment and they are the ones that actually navigate. You can abstract out this concept, but I couldn’t find a good abstraction that would make the code easyer to understand..
There are some problems with this implementation when you start to implement multi-module
I know that you can invert the control, but after going back and forth with different abstractions trying to invert the controll to the presenter (ViewModel), I got to the conclusion that simple emmiting the event to the fragment / activity was easier to understand. Specially when you are injecting different destinations.
👍 2
a
For me I found out emitting a UIEvent (which is a one-off event like Showing snack bars or toast), is the most suitable solution for me, in terms of easy to implement and understand.
i
I agree.
But who actually navigates is the fragment in my case. He is observing those UiEvents and some of them are handled as navigation events.
The ViewModel doesn’t even know that the UI will navigate in my case
I really tried to introduce this “Router” concept in my view-models, but IMO, it did not made the code easier to understand and extend.
And I am not very fond of this Cicerone implementation: having to always call it onResume + onPause, than injecting it with dagger in the view-model + injecting custom destinations, etc. It seems harder than simple emmiting an event “OnForwardCommandClick” from the view model and simple using a fragmentStack operation?
a
But in case of Single Activity application, you'll have it only in one place, no?
i
You will have only one Navigator for the app?
Doesn’t you need to install a
Navigator
on every onResume?
I imagine that you need to inject different
Navigators
for different features…
So, now you will need to introduce probably a new abstraction?
s
Putting navigation in the Use Case layer would make it really difficult to test, I would think
c
Use Case layer is responsible for changing or representing state. The layers out from there may know how to act on a specific state. The representation and navigation is in the UI. So the UI must know how to best represent the state in some cases you want to let the UI know which events are allowed for current state because it is tied to a specific state model. Then that information becomes part of the representation of the state and the UI doesn't have to replicate the decision. I use this when I do a finite state machine. I allow for the FSM to provide a list of events that should be possible. The UI doesn't have to figure it out. Show/Hide or Enable/Disable events as best fit the UX.
đź’Ż 1
f
Lots of different opinions. @Ahmed Ibrahim use whatever works best for you and as long as it is unit testable