So far, we've done everything in memory only. This lesson will show you how you can hook up with external asynchronous APIs, using Retrofit.
Thank you, I'm really happy you found the material helpful. :)
When thinking about architectures in general, I tend to think of it less in terms of pros-and-cons, and more in terms of "gotchas".
MVI uses still fairly novel programming patterns. Reactive programming, unidirectional data flow, and functional principles. Those patterns bring to the table a lot of desirable things. But, by being relatively "new", they bring some risks to the table.
How much experience does a team have with those new concepts? How motived are folks to learn new things? How much legacy code are you dealing with? Is this a greenfield app? Architecture choices by nature will involve teams of individuals.
The number one gotcha on my list is adoption. But to be fair, that gotcha applies to MVVM as well as MVI. MVI is more niche, so in my opinion, a team adopting it needs to be clear on the benefits.
My number two gotcha would have to be regarding state management. I believe a big key to a successful MVI implementation lies with modelling state in a very clear, deliberate manner. That means taking the time to model your state transitions, and when appropriate taking the time to modeling a full-fledged state machine.
Not doing this could lead to inconsistent state creeping into your model, which again, is a problem not exclusive to MVI.
There are a few options there. It depends on what you're exactly aiming for.
The key is to have "one-time" signals for your state transitions. What I mean by that is, you'll want to avoid starting to emit viewEvents every time
onResume() is called. Anything that's linked to configuration changes is basically going to cause problems.
If you look in the sample code, those kinds of "transitions" are always managed at the "source". When we start editing a Task, for example, we do it from the moment the user triggers "edit-task", when they click on an item in the list. We trigger a "clearing" of the edit state when the user presses
back on the toolbar.
If we'd be trying to load the list of Tasks right off the bat, we'd usually do that as part of the app-initialization sequence. Meaning, a trigger to load the current TODOs (from network or from disk, or disk then network) could be triggered from our
App class itself, in the background.
So I am trying to implement navigation by creating a navigation model store, and a navigation intent factory. The model store would hold the currently active screen, and the application would implement StateSubscriber and would do the startActivity stuff. The only problem I am facing right now, that when I am trying to start the task editor activity, I have to call the navigationModelStore.process(changeToTasksIntent), and the taskEditorModelStore.process(transitionFromClosedToEditingIntent), and this feels a bit like duplication.
How would you implement a navigation model store / navigation intent factory? (Or is doing this even recommended?)
Also can it be correct to reference one intent factory from an other intetet factory?
Thanks for the response in advance :)
Edit: From your answer to my other question (and some googling around) I found that this pattern is not as strickt as I thought. I think I will leave the in app navigation out of the MVI framework and let my views handle that. (I think I will still have state machines for my views, but the navigation would not depend on these state changes)
I see that even redux (which as I heard is also a very MVI like framework) suggests to use react's navigation instead of redux: https://reactnavigation.org/docs/en/redux-integration.html#can-i-store-the-navigation-state-in-redux-too
Yah, navigation is a tricky one. Depending on what you're doing, you might end up running afoul of what the platform is trying to do for you. You have to think about a lot of Android platform-specific things (back stack and so forth), and we're not even talking about how using Jetpack Nav library might change this story.
I feel it's safe enough to have the "View" listen to the model (in our example,
TaskEditorModelStore) and, based on its state (CLOSED|EDITING), trigger calls to whatever navigation framework you use to "move to the right place".
Then, like you suggest, by letting the view "manage" the Nav system calls, we're effectively saying Navigation is a "view concern", and we keep it out of our Model/Domain layer. And with Jetpack Nav components, I feel delegating that work to Google gives the best ROI.