Why this architecture is so important and why you need to learn more about it?
Well, before we start, let’s begin from the very early. This architecture was built by Paolo Soares and Cong Hui, both from Google and presented for the first time at 2018 DartConf (January 23–24). See the complete video.
To master this architecture, before anything, you must know how to use Streams, use them correctly and understand the meaning behind reactive programming.
TL;DR, it’s a pipe, with an input (sink) and an output (stream). That’s it. Understand that when I say input and output, in terms of code, I want to mean that the onPressed function from a button will execute, it’s the sink, because, I’ll be adding something in that pipe, and could be anything and everything. While on the other side, my output (stream), could be a text that’ll be presented to the user which will change after each button press.
Here I show a very good and practical example:
As you can see, on the FAB’s onPressed, I’m changing my _counter variable as long as I keep pressing it. While in the StreamBuilder it receives my output (_counterController.stream) and I render the last value on the text widget, which is my snapshot.data.
Line 4. I initialize my controller, int type, because I don’t want it to be a dynamic.
Line 8. My dispose() function receives the .close() param from my StreamController that I created, with that, I can free it when I’m no longer using it. Avoiding, memory leak and lack of performance. You MUST do this, always.
Line 25. Add the pipe’s output, in other words, what I want to show to my user’s device. In that case, the output is an int value, which will change as long as I keep pressing the FAB.
Line 26. Initialize with a random value, could it be 10, 20, 30, it’s up to you.
Line 27~29. Created the builder that will receive the context from this whole component and a snapshot, which is the last message that the Stream received so I can show to the user the correct value.
Line 38. Created the input that will add the values to the pipe. Because this example is very simple, you can see that I’m always changing my _counter’s variable value.
That’s it, this is the most simple and basic example showing how you can transform your application that make use of setState(), which is not so useful when you have a complex application and we’re going to see the reason of this very soon, to make use of streams.
setState() vs Streams
You may now be asking yourself: “Why this guy didn’t make use of the setState() to build that? Why he make use of streams?” The answer is pretty simple and straightforward: Performance and efficiency.
Details, details and details…
I’m not saying that the use of setState() to build your apps it’s something bad, or to use streams is a better option, however, there’s a but, and this but come from the size of your application, and when I’m not talking about the size in MB, I talk about the complexity of it.
Think with me for a sec, imagine that you have your UI all made it, changing some widgets values or appearance with setState(), until now, no problems with that, right? Well, in case you’re new to Flutter or didn’t have time to learn the difference and that’s why you end it up here, I’m going to tell you why the use of setState() in a medium/large application is not efficient/useful.
At each alteration that you make in a widget using the setState(), you not only will rebuild that specific widget, but ALL your UI, again, which means that, for a large and complex application that has a bunch of animations, composed widgets, some other showing info from an external API, it’s a huge lack of performance and can’t be allowed from a certain point of development.
Now, of course, if your are trying to build your MVP to show to some client or a friend or even just to have notion and knowledge, it’s very useful to make use of setState(). Although, as soon as your application become to be more and more complex, one good way to handle the state of it it’s to make use of reactive programming and in case become even more complex, learn and apply the BLoC Architecture.
So, the use of Streams is the more recommended?
Yes and no. With that been said in the last paragraph, it depends, but of course, I’m sure that you as a programmer that are reading this article, don’t want to stay always doing the same stuff and expect a different result, am I right? That’s the definition on insanity. I’m sure you and to level up your skills and become more and more highlighted from the others.
Answering with more details the title’s question, the use of Streams it’s the most recommended always, in my opinion, why? Because let your code more cleaner, legible and very easy to maintain for future programmers or even yourself in some part of the future.
I learned how to use Streams, now what?
So you learned how to make use of Streams in your application and don’t know where to go? It’s very simple, now you going to learn how to manage your application’s state using the BLoC Architecture.
Have you ever imagined all your UI separated from your business logic? I believe that you have made code which everything, absolutely everything was included in the same file, your UI, business logic, API requests. Anyway, a total mess that sometimes you have difficult to find what you’re looking for.
However, BLoC came to help you guys and if you stop and study with interest, you’ll see that it’s very simple to understand and to apply in your app’s development.
Let’s follow the counter example and add the BLoC Architecture in it. Even though it’s a simple application, the article’s main object it’s that you can learn and understand easily.
- Create the Provider class
2. Create the BLoC for this counter
Line 3~4. Create the class and our counter variable and set it to 0.
Line 6. Created a StreamController which we’ll make use to add value and stream the value out.
Line 8. We create a shortcut from .sink.add parameter.
Line 10. We also create a shortcut from .stream parameter.
Line 12. Create a function that will increment the counter variable.
So far so good, right? I hope that you had understood, it’s pretty simple and we have did ’til now.
We’re almost there, now, we need to change some few things in our UI. Let’s get back to it.
In the component which initialize the MyHomePage, you need to change his parent to this:
Now, our MyApp() has the Provider as his parent.
Spot some differences from the very first example using Stream, to this one, using the BLoC Architecture.
- We don’t have the controller been instantiated anymore.
- We don’t have our dispose() method to free the stream when we no longer need of it.
And last but not least, our component it’s complete Stateless.
Keep up, now, we need to glue all the pieces to make this work, don’t lose your focus.
Lines 2. Import our Provider that we created.
Line 8. Create inside our widget, the bloc that will receive a BlocProvider, with that, we’re gonna have access to all of our gets that we built in the Bloc.dart.
Line 21~24. We set a initial data to our stream builder (0) so it won’t return a null value at start. Then, we set our stream shortcut, remember? Now, we interpolate the snapshot.data in the text.
Line 35.Call the function that will execute the _counter’s variable increment. And then… Increment it!
Apply this architecture isn’t difficult, difficult it’s to find people that knows how to pass this subject in a objective and directly way which I’ve tried to do it here. I hope that have been of a great help for you guys, programmers that wish to level up and be sure that learning what was said in this article, you only have to grow and become a better developer.
Any thoughts? Was hard to learn? Complicated? Leave comments below, constructive criticize are always welcome.
This example’s code can be found here.