using Bloc by Example
On February 9th, 2019, Felix Angelov wrote a wonderful article on the Flutter package, flutter_bloc, demonstrating how to manage multiple ‘Business Logic Components’ (or BLoC’s) to implement dynamic theming, pull-to-refresh, and much more. This package helps implement the BLoC pattern, and the article demonstrates this with a simple Weather app.
The article is available here:
Now again, Felix’s focus in the article was the managing of more than one BLoC in an application. Therefore, this Weather app has one BLoC responsible for the fetching of weather information, another for supplying the ‘theme’ or color scheme to match a particular forecast, and finally another BLoC is involved in the app’s settings: toggling the temperature between Fahrenheit and Celsius. As it happens, such demands don’t exactly take full advantage of what Bloc has to offer.
It did, however, allowed for an alternate approach. Since the app involved extensive user-interaction with the fetching of data, dynamic theming, pull-to-refresh, etc. all initiated solely by the user, streaming is not necessarily a vital trait for such an app and could readily be done without streaming. For example, such an app could be done with the Flutter package, mvc_pattern.
This is no reflection on Bloc. Far from it. With one change to the app’s specs. to require ‘real-time’ weather forecasts, for example, I would suggest you’re half way there if you already had it implemented with Bloc. An app requiring the intermittent if not constant streaming of variant data is right up in Bloc’s wheelhouse. However, with the app example’s current specifications, and with Felix’s permission, I wrote the very same Weather app, blatantly using much of the existing code from his example app to convey another approach.
You see, some developers, today, may not have personal experience with MVC. Not directly anyway. After all, it is a 40-year old design pattern. However, they likely have indirectly been exposed to MVC since many of today’s design patterns are its descendant. This article is an attempt to further explain MVC using an Bloc example as reference. Their implementations may vary, but the general concept they follow is the same.
Let’s get started!
Right off the hop, I’ll assume the reader is somewhat familiar with Bloc and with MVC. However, again, since my target audience are those developers with little or no experience with MVC, I will only suggest, right here and now, to first read the article explaining my interpretation of MVC as it was implemented in the Flutter package, mvc_pattern:
Hey! Your’e back! Great.
An additional comment before we continue. I will present a number of screenshots in this article. Unlike embedded gists, screenshots readily allow me to display segments of code of interest. Easier to read too in my opinion. However, as always, the reader can tap/click on the screenshots where they are then directed to a gist version or directly to code on Github allowing them to easily copy the code, for example, if they wish. The screenshot captions are also links to Github or to Gist source code.
Like the Bloc implementation used by the Flutter package, flutter_bloc, the build() function of State Objects serve like the ‘View’ aspect of MVC in the Flutter package, mvc_pattern. Such build() functions are then peppered with one or more instances of a ‘ Business Logic Component’ (be it a BLoC or a Controller). It is they that then supply the ‘data’ to be displayed in the build() function.
Looking at the ‘main view’ or home page for both app versions (It’s a StatefulWidget. One named, WeatherHome; the other named, Weather, respectively), You can see both Felix and I decided to instantiate our respective ‘Business Logic Component’ in the StateWidgets’ initState() functions.
Looking further down the respective StatefulWidgets, both build() functions are, indeed, dotted with instances of their ‘Business Logic Components’ responsible for responding to all the user-interaction and controlling what is then displayed as a result. Looking at both screenshots side by side, you’ll see their implementations may differ, but the results are the same. Note, I will not ‘get into the details’ describing their respective implementations in these build() functions — being beyond the scope of this particular article.
Further, both versions utilize the ‘theme’ property of the MaterialApp class. That class is instantiated back in the very first Widget created for both apps respectively. In the Bloc one it’s called, App. In the MVC one, it’s called WeatherApp. But what’s in a name? In both versions, we then move on to call on the their respective ‘home’ widgets — class WeatherHome and class Weather respectively. Those you’ve already had seen above.
It is here, in these ‘app’ classes, where you’re introduced to the second BLoC and Controller used in each app. Both are responsible for providing the ‘Theme’ to accompany the next weather forecast retrieved from the first pair introduced above — when a city location is selected in the app. Highlighted with little red arrows, you see below where each is injected into the Flutter’s own native framework giving each access to their respective State objects. The second set of little red arrows show where the property, theme, is assigned their respective values.
The third and last BLoC in Felix’s example involves determining whether temperatures are to be displayed either in Fahrenheit or in Celsius. Below you can see each version retrieving and applying the current setting. The default setting in this simple Weather app was in Celsius.
Note, I didn’t find the App’s Settings implemented any further at that time I retrieved the example code from Github. With that, I took the liberty to whip up a simple drawer displaying a toggle switch to move between Celsius and Fahrenheit.
Supplying such a menu allowed me to then implement that third and final BLoC in the Bloc version as well as its Controller counterpart in the other version. And so, below are the two versions used to present the user with a toggle switch if and when they want to change the temperature reading from Celsius to Fahrenheit or back again. Again, highlighted with little red arrows are where the current unit settings are retrieved in both versions, where the unit is toggled, and where the app screen is ‘refreshed’ to display the new temperature reading.
Note, the Switcher class I just made myself — to pass on two specific values to the Drawer.
Back to the second BLoC and Controller used in each app — again, the ones supplying the theme for each new forecast. Both actually call back to the State object they were originally associated with. Specially, both call their State object’s setState() function. Let’s see where they do that.
At the start of the apps, with the first StatefulWidget passed on to the runApp() function, a BLoC and Controller is instantiated and ‘associated’ with a State object. They’re the first ones instantiated but were the second ones introduced in this article: The ‘Theme’ BLoC and ‘Theme’ Controller.
Below are those StatefulWidgets passed to the runApp() function. Again, you can see where the respective BLoC and Controller is ‘linked with’ their State objects. With the Bloc version, the class object, BlocBuilder, is itself a StatefulWidget. It’s that StatefulWidget’s State object the BLoC class, ThemeBloc, is associated with. The MVC version, simply supplies its Controller to the very first State object encountered, _WeatherAppState.
In both versions, you can see in the first pair screenshots below where their respective ‘weatherChanged’ events are initiated. As a result, you can see in the second set of screenshots below, where the function, setState(), is called inside their the respective boilerplate's. In other words, both approaches have the mechanism in place for their respective ‘business logic components’ to call their associated State objects to rebuild their Widget trees.
This Github repository will have the Weather App implemented with this alternative approach. In fact, as you may already have realized, Felix’s Weather App example code is in there as well — the code I originally retrieved back on Monday, February 11th, 2019 anyway. Going to the file, main.dart, you could alternate between the two approaches if you wish.
This article does provide an alternate approach, but the idea behind them are the same. Bloc would suit just the same if not better…particularly with the ‘real-time’ feature. The main message here is that, from reading this article, you can see Bloc follows the MVC design pattern with the explicit effort to separate the business logic from presentation layer and from the data layer. It’s just that, as in Life, there never is just one answer. Never just one approach. There’s options out there. Options developers should always be aware of and open to.