I came from MVC and VIPER world and now I am new to Flutter cross-platform development. I really like declarative things it brings (like SwiftUI for example does as well). I see a lot of advantages in React architecture that Flutter uses to update UI with the most recent data. Though I still try to understand a conception of widgets. In my head, a word widget is more about UI things, but the documentation says that all in Flutter is a widget.
Let me highlight a simple example. Also, let's forget about declarative UI things.
In the iOS world using Objective-C or Swift, we usually separate a lot of layers such as data layer, UI layer, service layer, some helper layers and etc.
As you may notice we can't simply call these layers widgets, but looks like flutter can, but I may be wrong.
In the iOS world, I would like to use VIPER or some similar architecture pattern to separate different layers or add some services which request some data for me or do save it into the database.
What are the similar approaches or architecture patterns which I can use to follow best practice recommendations to achieve the best result, because as for me if we call some service which saves data to the database as a widget it's a bit strange. I would like to call it more service rather than a widget.
Do I need to write a widget for all such things? Or did I get it wrong?
Do I need to write widget for all such things? Or did I get it wrong?
Let me start by saying that flutter is flexible enough to allow you to adopt any pattern you have been using before and from MVVM, MVC, Redux, Mobx, Bloc, Provider, Riverpod etc pp there are many patterns out there which you can lean on.
Q: Do all services have to be widgets?
A: It depends.
Lets talk about "getting" the services first (dependency injection)
Using Widgets is just one way of doing dependency injection in Flutter which has the huge benefit of being scoped (only available to the children of the widget) and also of being disposed when this part of the widgettree is no longer needed (a bit over simplified).
There are other DI systems like getIt which don't rely on the widget tree - and you can do fancy stuff with getIt which is cumbersome to do in many of the others which rely on the build context to provide access to the object.
Imho in most cases you would not want to have your logic/ service in a widget but in a separate class which is then "provided" via a widget (e.g. using Provider, or by injecting it via getIt into the widget).
About "best practices":
There are many cool patterns which all have their pros and cons.
If you have a big team or the developers are changing often you might want to use a more rigid and biased system like BLOC (using the bloc library) - if you are solo or have enough time on your hands to do your own research, there might be patterns which better suit your needs. There is no one size fits all answer to this question.
For further research I would point towards the Flutter Architecture samples and the corresponding Github repo, there might be more examples in the Pull Request section
Related
I've seen many tutorials praising Bloc State management, what is so special about it and should I learn it as a beginner? if not is there any beginner friendly state management technique?
BLoC/Cubit
BLoC is great for complex state management for complex apps. However, inside the BLoC library there's a simpler way of managing state that's called Cubit (Cubit is sort of a subset of BLoC). Cubit is largely the same as BLoC except:
less boilerplate
doesn't use 2-way streams
This renders it much easier to learn, and a fantastic stepping-stone into a full-out BLoC driven state management solution.
Currently, my team and I are building a very complex app, and we use the principle: use Cubit's, unless there's a specific reason to use a BLoC. This has worked well for us (85% of our app is run with Cubit, 15% with BLoC).
In relation to other state management techniques, most people are probably going to recommend Provider or Riverpods (Riverpods = Provider on steroids). They are easier to learn than Cubit/BLoC. Except, only for simple cases (a few page app). Once your app gets complex (authentication, feeds, api calls, etc.) a Cubit/BLoC-based architecture is going to scale better and be much cleaner.
Additionally, the most-used state management system for production-level Flutter apps is BLoC/Cubit. So, if you're looking for a marketable skill, I'd default to that.
Helpful links:
Flutter package that contains BOTH BLoC and Cubit.
The tutorial series I watched to learn BLoC/Cubit (and recommend!).
I HIGHLY recommend watching this series as well that shows WHERE to put your BLoC/Cubit in an app to align with best practices and clean architecture.
Example app (understanding this will help you a lot):
Here's a simple 1-feature app I made as a proof of concept to show how Cubit specifically works. Read the project's README.md for context.
Conclusion:
Provider, GetX, Riverpods, etc. are all easier to learn and contain less boilerplate than BLoC, except they won't scale as well when your app gets more complex.
To help combat the boilerplate/complexity problem of BLoC, use Cubits instead of BLoCs in your design unless you have a specific need for BLoCs.
Cubits are quite easy to understand and can be used in most of the Flutter projects. For bigger apps I would go for Riverpod. Having independent providers gives a lot of flexibility, as they can be used in different parts of the app and you can make any future, use case or repository a provider.
I have wrote a tutorial with Flutter app on how to write a List - Details app using cubits, hooks and local database with Hive.
GETX - State Management
I would suggest Getx as I have been using it for 3 years and it's incredible.
It is effortless to learn.
I never encountered a need to use any other state management.
Features provided by GETX
State management
Dependency Injection
Theming
Clean Structure
Internationalization
Validation / Utils
Documentation
my question is about what approach to choose for app state management. Many walktrough talks about BLoC, RxDart, Redux etc.
My aim is to develop a simple app that download sometimes data from a server and keep using local storage (SQL in flutter) to handle the data (CRUD operations). Other involve few user data handled by shared preferences.
I don't need high performance / super asynchronous stream of data from a server(as shown in 90% of tutoral of BLoC logic).
Is truly neecessary to have an app state pattern and what can the best approach for my case?
Yes, BLoC, RxDart, Redux are good enough.
But we should choose the things on our requirement and here in this project, there is no need to use any three of these.
For state-management, you can use the provider package as this suits best to your requirement, and it's easy to use and implement
A very simple example to implement it is here
You can use the approach of Stateful Widgets, and do your process (in case you do not need a app with a high performance), but the best approach I would suggest is to use PROVIDERS, they are easy to implement, You can take care of the downloading process and the saving also in a easier and cleaner manner, the App will perform very well, and also works well with Stateless widgets (you can rebuild only the necessary parts in a complex widget tree).
But have your own research, and find out which will suit your App the best,
Happy Coding :)
My suggestion is to try to use a mix between Provider and BLoC, instead of using RxDart, Redux which requires too much boilerplate code and it is more used to manage streams.
The provider will allow you to share information between your widget tree, in an organized way and BLoC will help you to separate your logic from your UI, the best practice to grow in time.
I suggest content from this channel: https://codewithandrea.com/tags/provider/ He helps and provides good resources to implement an easy and understandable architecture background.
Am I wrong or if we just want to pass a value down the Widget tree, Provider is just an InheritedWidget with a dispose method?
Yes. Provider is indeed mostly features based on Inheritedwidgets.
If you want to make your own, then that's fine. But you'll quickly realize that, without provider, you'll have hundreds of useless repetitive lines.
Provider basically takes the logic of InheritedWidgets, but reduce the boilerplate to the strict minimum.
Provider is not a must, but should.
First of all, it's promoted by Flutter Team and flexible enough to handle almost any state-management solution.
It might not be fair to say that InheritedWidget with dispose because Provider has too many different use cases and inherits some optimizations probably you won't find anywhere else.
If you use InheritedWidget in large application, build methods always rebuilds whole build method. But with Provider you have Consumer widget which is can be very specific to control specific blocks of build method, so you have more efficiency. Also listeners have less complexity than InheritedWidgets'(O(N) vs O(N²)).
The problem is since Flutter was intended to be a UI framework at first, the default state management solutions are also UI oriented.
Lastly, since you'll need different state-management patterns for different projects, one package-for-all scenario is invaluable imo.
The Flutter docs have a good section about this where they're talking about state management in your app (a big part of which is passing values down the tree).
Flutter has mechanisms for widgets to provide data and services to their descendants (in other words, not just their children, but any widgets below them). As you would expect from Flutter, where Everything is a Widget™, these mechanisms are just special kinds of widgets—InheritedWidget, InheritedNotifier, InheritedModel, and more. We won’t be covering those here, because they are a bit low-level for what we’re trying to do.
Instead, we are going to use a package that works with the low-level widgets but is simple to use. It’s called provider.
So as of late 2021, it seems the recommendation is to use the provider package unless you need lower level access- in which case you could use the Inherited* widgets. For example, if you wrote your own version of provider then you'd need that lower level access.
The doc I quoted above is at https://docs.flutter.dev/development/data-and-backend/state-mgmt/simple#accessing-the-state
I need manage the states globally, I find a lot of way, in terms of managing the state by using Provider bloc pattern redux and etc.
But actually I dont know, which one is faster and performant?
Example: I am working on chat application, which I have to manage socket connection messages online offline status all as globally. the states need to be accessible from all screen, like ChatList screen, ChatBox screen and more...
I didn't test them all performance wise. And i do not think it will make much of a difference.
Provider works with inheritedwidget as scoped model i think.
I love the streams for the versatility of the data flow.... i think the key part for performance is to keep the rebuilding/painting of the widgets that require it at the lowest level of the tree.
get_it package should help you to keep those streams accessible everywhere, is a great simple package to keep neat model access, regarding the state management solution.
For instance, i believe that generating statelessstateful widgets instead of functions that returns widgets to make the layout, provides more performance, for the separation of buildcontexts.
In any case, the framework is super optimized and performant... if u run into any issue, u can easily track it down with the devtools and the community is very supportive.
Btw, take my basic reply with a grain of salt, as I've been only playing with flutter/dart for a week.
I'm creating a new app with Flutter, and I'm trying to design it, separating the business logic from the view.
I've read about Bloc and MVVM (I know there are other patterns but these were the ones I preferred), but I don't understand the differences between them. They look pretty much the same to me.
Does anyone can help me understand them?
Looking at this illustration for MVVM (source):
You can see that there are seperate data and business logic models. However, using BLoC there is not really a distinction like that. The classes that handle the business logic also handle the data, which can also apply to MVVM.
To be fair, there really is not much of a difference. The key part to take away is the same for both: Isolating the business logic from the UI. Hence, the implementation of either of the two will look very similar, i.e. using Stream's and StreamBuilder's.
Additionally, there are packages that make working with Stream's easier, e.g. rxdart which is what the Flutter team uses as far as I am concerned.
BLoC and MVVM seemed to be different when BLoC was introduced, but that differences faded away as BLoC implementations changed over time. Right now the only real difference is that BLoC doesn't specify a separate presentation logic and business logic, or at least it doesn't do it in an obvious manner. Presentation logic is the layer that understands interactions between UI elements and the business part of the application(Presenter job in MVP). Some BLoC implementations put presentation logic into BLoC's, some others into UI.
The NEW THING in BloC was that it should not expose any methods. Instead, it would only accept events through its exposed sink or sinks. This was for sake of code reuse between Angular Dart web apps and Flutter mobile apps. This concept was recently abandoned because we don't really write Angular Dart web apps and it is less convenient than regular methods. Right now Blocks in official BLoC package expose methods just like good ol' VM.
Some would say that BLoC should expose one Stream of complete state objects, while VM can expose multiple Streams, but this is not true. Exposing one Stream of states is a good practice in both approaches. At first, official Google BLoC presentations presented BLoCs implemented using multiple output Streams as well.
One interesting difference that seemed to be a thing was that BLoC should communicate via events not only with UI but also with different parts of the application. for example, it should receive an event after receiving Firebase notification or when Repository data changes. While this seems interesting I've never seen an implementation like that. It would be odd from a technical point of view (Repository would have to know about all BLoC's that are using it???). Although I am thinking about trying out such an implementation that would be based on EventBus but that's completely off topic :)
They are not quite the same, actually... MVVM implies databindings between the view and the viewmodel, which means, in practice, the view objects mostly are the ones commanding the viewmodel. MVVM seems to me a simplification of MVC, to show the model "as is" behind the scenes. For example, Xamarin largely uses MVVM and the controls on the screen like checkboxes, textinputs, etc, all do modify the modelview behind the scenes.
You may already starting to see a problem here: if you change the UI you may have to change the MV as well. Suppose you have an entry number that must be between 0-255, where do you put this logic? Well, on MVVM you put this logic on the view. But you must put these locks on the modelview as well to guarantee data safety. That means a lot of code rewriting to do the same thing. If you decide to change this range, you have to change in two places, which makes your code more prone to errors. Disclaimer: there are workarounds for this but is far more complicated than it should be.
On the other hand, BLoC works by receiving events and emitting states. It doesn't care (although it may) from where the event came from. Using the same example from the above, the view would signal an event to the bloc/controller with "hey, my number changed!", the bloc then would process this new event and, if suitable, emit a signal to the UI: "hey UI! You should change! I have a new state for you!". Then, the UI rebuilds itself to present those changes.
For me, the advantage of BLoC over MVVM is that the business logic can be entirely decouple from the view, which is overall a better way to do things. As our modern software development requires more and more changes in the UI (being different screen sizes, densities, platform, etc.), having the UI side decoupled from the models are a fantastic feature to code reusability.