-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Should Simple Stack be used in new projects #279
Comments
Hello, Simple-Stack continues to be maintained, and we still use it on old and new projects because there is less "magic tooling" involved (read: there's no reflection, no code gen, no annotation processing, no gradle plugins, it's literally just code), other than state restoration the whole thing can be used as-is in unit tests, and it still allows easier control over your navigation history, and it still allows for "less friction" to share data between screens. The one potential downside is that Google stopped creating frameworks with the intention of them being "Open for extension by third parties". So if you look at However, the new Fragment behaviors for "in-app predictive back" is designed in such a way that it would only work with Fragments that are being used exactly as Jetpack Navigation does it. If you're for some reason forced to use Hilt, then Hilt's scoping is much more rigid, and doesn't account for the ability to create scope inheritance. That, and Hilt's NavBackStackEntry-based integration only works with NavBackStackEntry, which is their own internal class. You can't just provide "something similar" unless you actually rewrite all relevant code. Anyway, as far as I know, the people who use / have used Simple-Stack are satisfied with it. There's a much lower learning curve, and the features are more powerful. Even the Compose integration was more powerful than Navigation-Compose for years despite being what I think of as a proof-of-concept. However, there is less reliance but also less out-of-the-box integration with certain Jetpack things. This is a double-edged sword; technically having no dependencies on Jetpack makes this library less fragile, but it also intimidates people because, well, there's just so much less stuff to work with that they think it "knows less". You have to be in a higher position to say, "yes, we will ditch the official ecosystem (that keeps getting either deprecated or rewritten every 3 years anyway) and instead rely on this guy's code that he uses in single-activity projects to fix issues and simplify development). For whatever reason, even though the Google teams are also around 2-3 people on a given package (except Compose), seeing "google" there instead of "zhuinden" somehow makes people trust it more (even though that just means it's more likely to get dropped, as Google keeps dropping support for their things once they get tired of it). Personally, I would say, check the feature set and see if it suits your needs. There are teams that use simple-stack as implementation detail (https://github.com/inovait/kotlinova) and they are also satisfied with it afaik. |
TL;DR is that we still use Simple-Stack and it is still simpler to manage state with it, than when in Jetpack Navigation you're defining actions, routes, all are always available but most of them are invalid states. Hypothetically it would be possible to restrict Simple-Stack's feature set by making it an implementation detail of a Jetpack Navigation navigator, however I don't see why you'd want to just make things harder for yourself. The one thing that Navigation does have over Simple-Stack is out of the box " |
Thank you, very detailed and kotlinova seems very interesting |
Yes, kotlinova does look interesting, and the 2.8.0 feature update was added pretty much because kotlinova requested it, although I personally don't use kotlinova. We use a setup very similar to what you see in the FTUE samples. |
I've spent some time going through the samples (very clean code once you start to understand albeit very different from what I'm used to) and I have a few more questions now, mostly regarding migrating from Jetpack in an existing project.
|
That's a question of how much you rely on Jetpack Navigation's feature set. For example, their bottom navigation works differently than how we do it (nested fragments), their deep-linking API is different, and they have dialog destinations which are not part of the StateChanger implementation by default. The Navigation dialog destination support used to have edge-cases that were tricky to resolve on their side, now their code seems to have improved in that regard (because they made Navigation be async / state-based in order to support Compose transitions). Honestly, Simple-Stack does "less things". This makes it more robust, but it also means sometimes you have to do something they have already written, and vice versa. For example, it's easier to just say I don't tend to migrate tooling that "works". I have migrated custom navigators to be replaced with Simple-Stack however to fix bugs. Having multiple Activities within the accessible app flow is the most intrusive architectural decision that is very hard to undo the effects of.
I've been using Fragments in projects lately. Custom views are still nicer for when you need to support complex transitions.
You're also tied to an "explicit service locator" by using There is fundamentally no difference between how the two work. In fact, having to use You could theoretically create something like a custom component like Personally I find all of these options to be much more work than it's worth. The boilerplate would be to interop with Hilt's extremely rigid (and limited) APIs, especially knowing that it wouldn't be able to support scope inheritance, it's not part of their design. This is why Anvil exists in the first place. I don't use Anvil, but it would be easier to support Anvil as its scoping is not rigid (see kotlinova which uses it). TL;DR you can use Hilt but it is kinda difficult, and it is because of Hilt's limitations. Also, you don't pass ServiceBinder to scoped services, so that's not actually "explicit service location" it's manual IoC. The constructor gets the arguments it needs. This is something I've run into criticisms of, but I find it's because people just want to see code generation here whether they need it or not. I have no intention to include code generation (#223).
Simple-Stack works within an Activity. Personally I believe that creating "loginActivity/registrationActivity" breaks deep-linking potential and control over your task stack, but you can still somewhat work around it as long as you only have 1 Activity on your task stack at a given time. Honestly, sure, But I have used simple-stack to manage fragments in a multi-activity app within various activities, the option is there. The only thing you might need to guard against is that |
If one were to want to use code-gen-based DI by any means, then Anvil is much less restrictive/restricted than Hilt. |
I only use Hilt because I'm a simple man and almost always all I need to do is write I also had to work with Kodein once and it seemed worse than Dagger, and I've never tried Anvil. Regarding multiple activities in the project, I think it ended up this way after I had issues with Jetpack navigation and it turned out easier / cheaper to implement different flows as different activities, ha. The project is not even MVP yet and we are redesigning most screens so I want to try something else to speed up further development. |
Well technically you can still use Hilt+ViewModel but you will lose the scope inheritance and "advanced" lifecycle management that ScopedServices give you. And the the cost of creation of a ScopedService compared to the It is theoretically possible to create subcomponents and whatnot per each scope node and then get those scoped parameters into the ServiceBinder but it's so much more work than just using it like how it's done in the samples that I've removed Dagger from all samples since. It's somewhere in the commit history, not really worth finding it. I used to put the services and the Dagger component in the ServiceBinder as a service for "lookup" below, wasn't really worth it in the end. |
Hmm, to be honest I simply don't understand. I don't really use any advanced Dagger features in my projects, haven't been for years with Hilt. I'm a simple man 😁 Not having to manually add services to GlobalServices and then also write lookups is so convenient, but then again it's also a matter of a few lines in pretty much any app. |
It seems convenient and then you get hit by the quirky build errors in kapt, to replace 2 lines of code with a https://youtu.be/5ACcin1Z2HQ?si=xvqbBSCHEVtR7KD2&t=1449 Anyway, ScopedServices have always been an optional aspect of Simple-Stack. I believe them to greatly simplify things because of If you wanted to use Hilt with GlobalServices, you'd need to get a reference to each app-scoped instance and But the navigation APIs alone are already powerful and versatile enough that it's easier to use than NavGraphs, NavGraphs are very limiting because once you have a subgraph, you can only access its start destination with 1 action. |
Very informative. I have perhaps one last question, is there a tutorial on how to handle dialogs? I can find discussions here and I think there was something in the samples, but not too specific. And dialogs are such a nuisance. |
I've been using either AlertDialog or DialogFragment depending on whether something should survive config changes or not; there's nothing specific to dialogs in Simple-Stack out of the box. I don't tend to put it on the backstack because then you start needing to handle multiple types, which I know jetpack navigation does internally, but dialog destinations really are a trick in regards that their parent also needs to be created and shown anyway - it is a special hierarchical state if extracted. My favorite way to do Dialogs was DialogFragment + But a fun thing about DialogFragments is that they have Context, so they can access the Backstack, so they can access implicit/explicit scoped services using |
Nice, makes things easier. I'll make use of that. Thank you for all your replies. |
Thank you for your contribution to Android. After reading your numerous comments and posts on the state of Android development I came across this library.
However I'm sure if I should use it in my new project. Back in 2020 you mentioned somewhere that Simple Stack and Jetpack's navigation had become more or less equal feature-wise. It's been 3 years.
So my question is, would you advice using Simple Stack in 2023 over Jetpack, and of course why?
The text was updated successfully, but these errors were encountered: