Thanks! We'll be in touch in the next 12 hours
Oops! Something went wrong while submitting the form.

How to build High-Performance Flutter Apps using Streams

Performance is a significant factor for any mobile app, and multiple factors like architecture, logic, memory management, etc. cause low performance. When we develop an app in Flutter, the initial performance results are very good, but as development progresses, the negative effects of a bad codebase start showing up.  This blog is aimed at using an architecture that improves Flutter app performance. We will briefly touch base on the following points:

1. What is High-Performance Architecture?

1.1. Framework

1.2. Motivation

1.3. Implementation

2. Sample Project

3. Additional benefits

4. Conclusion

1. What is High-Performance Architecture?

This Architecture uses streams instead of the variable-based state management approach. Streams are the most preferred approach for scenarios in which an app needs data in real-time. Even with these benefits, why are streams not the first choice for developers? One of the reasons is that streams are considered difficult and complicated, but that reputation is slightly overstated. 
Dart is a programming language designed to have a reactive style system, i.e., architecture, with observable streams, as quoted by Flutter’s Director of Engineering, Eric Seidel in this podcast. [Note: The podcast’s audio is removed but an important part which is related to this architecture can be heard here in Zaiste’s youtube video.] 

1.1. Framework: 

  Figure 01

As shown in figure 01, we have 3 main components:

  • Supervisor: The Supervisor wraps the complete application, and is the Supervise responsible for creating the singleton of all managers as well as providing this manager's singleton to the required screen.
  • Managers: Each Manager has its own initialized streams that any screen can access by accessing the respective singleton. These streams can hold data that we can use anywhere in the application. Plus, as we are using streams, any update in this data will be reflected everywhere at the same time.
  • Screens: Screens will be on the receiver end of this project. Each screen uses local streams for its operations, and if global action is required, then accesses streams from managers using a singleton.

1.2. Motivation:

Zaiste proposed an idea in 2019 and created a plugin for such architecture. He named it “Sprinkel Architecture” and his plugin is called sprinkle which made our development easy to a certain level. But as of today, his plugin does not support new null safety features introduced in Dart 2.12.0. You can check more about his implementation here and can try his given sample with following command:

CODE: https://gist.github.com/velotiotech/023bbd24c8f112ae7b41e7b71ed9b922.js

1.3. Implementation:

We will be using the get plugin and rxdart plugins in combination to create our high performance architecture.

The Rxdart plugin will handle the stream creation and manipulation, whereas the get plugin can help us in dependency injection, route management, as well as state management.

2. Sample Project:

We will create a sample project to understand how to implement this architecture.

2.1. Create a project using following command:

CODE: https://gist.github.com/velotiotech/8c0f694a82eb2e37be65c787639d8da5.js  

2.2. Add these under dependencies of pubspec.yaml (and run command flutter pub get):

CODE: https://gist.github.com/velotiotech/1e09c87ca06e18d99efe537bb8847b99.js

2.3. Create 3 directories, constants, managers, and views, inside the lib directory:

2.4. First, we will start with a manager who will have streams & will increment the counter. Create dart file with name counter_manager.dart under managers directory:

CODE: https://gist.github.com/velotiotech/8ac0068aa1a04f88443325997aa6418a.js

2.5. With this, we have a working manager. Next, we’ll create a Supervisor who will create a singleton of all available managers. In our case, we’ll create a singleton of only one manager. Create a supervisor.dart file in the lib directory:

CODE: https://gist.github.com/velotiotech/3ce6451859a5d54943314a34460a5a7b.js

2.6. This application only has 1 screen, but it is a good practice to create constants related to routing, so let’s add route details. Create a dart file route_paths.dart:

CODE: https://gist.github.com/velotiotech/6e0b6abd2719e6980174e770cb068a4a.js

2.7. And route_pages.dart under constants directory:

CODE: https://gist.github.com/velotiotech/707c6e4026daf8d24a1f09e78f5c5b5e.js

2.8. Now, we have a routing constant that we can use. But do not have a CounterPage Class. But before creating this class, let’s update our main file:

CODE: https://gist.github.com/velotiotech/e2931f43d9bc6fda4cdb486374cd6403.js

2.9. Finally, add the file counter_page_controller.dart:

CODE: https://gist.github.com/velotiotech/413c9f3a173b060b03d794d21504906d.js

2.10. As well as our landing page  counter_page.dart:

CODE: https://gist.github.com/velotiotech/79ea2c811b70b0f49ad0e771adb2b235.js

2.11. The get plugin allows us to add 1 controller per screen by using the GetxController class. In this controller, we can do operations whose scope is limited to our screen. Here, CounterPageController provides CounterPage the singleton on CounterManger.

If everything is done as per the above commands, we will end up with the following tree structure:

2.12. Now we can test our project by running the following command:

CODE: https://gist.github.com/velotiotech/c9e1b5a8eaf030195699243b47df57f4.js

3. Additional Benefits:

3.1. Self Aware UI:

As all managers in our application are using streams to share data, whenever a screen changes managers’ data, the second screens with dependency on that data also update themselves in real-time. This will happen because of the listen() property of streams. 

3.2. Modularization:

We have separate managers for handling REST APIs, preferences, appStateInfo, etc. So, the modularization happens automatically. Plus UI logic gets separate from business logic as we are using getXController provided by the get plugin

3.3. Small rebuild footprint:

By default, Flutter rebuilds the whole widget tree for updating the UI but with the get and rxdart plugins, only the dependent widget refreshes itself.

4. Conclusion

We can achieve good performance of a Flutter app with an appropriate architecture as discussed in this blog. 

Get the latest engineering blogs delivered straight to your inbox.
No spam. Only expert insights.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Did you like the blog? If yes, we're sure you'll also like to work with the people who write them - our best-in-class engineering team.

We're looking for talented developers who are passionate about new emerging technologies. If that's you, get in touch with us.

Explore current openings

How to build High-Performance Flutter Apps using Streams

Performance is a significant factor for any mobile app, and multiple factors like architecture, logic, memory management, etc. cause low performance. When we develop an app in Flutter, the initial performance results are very good, but as development progresses, the negative effects of a bad codebase start showing up.  This blog is aimed at using an architecture that improves Flutter app performance. We will briefly touch base on the following points:

1. What is High-Performance Architecture?

1.1. Framework

1.2. Motivation

1.3. Implementation

2. Sample Project

3. Additional benefits

4. Conclusion

1. What is High-Performance Architecture?

This Architecture uses streams instead of the variable-based state management approach. Streams are the most preferred approach for scenarios in which an app needs data in real-time. Even with these benefits, why are streams not the first choice for developers? One of the reasons is that streams are considered difficult and complicated, but that reputation is slightly overstated. 
Dart is a programming language designed to have a reactive style system, i.e., architecture, with observable streams, as quoted by Flutter’s Director of Engineering, Eric Seidel in this podcast. [Note: The podcast’s audio is removed but an important part which is related to this architecture can be heard here in Zaiste’s youtube video.] 

1.1. Framework: 

  Figure 01

As shown in figure 01, we have 3 main components:

  • Supervisor: The Supervisor wraps the complete application, and is the Supervise responsible for creating the singleton of all managers as well as providing this manager's singleton to the required screen.
  • Managers: Each Manager has its own initialized streams that any screen can access by accessing the respective singleton. These streams can hold data that we can use anywhere in the application. Plus, as we are using streams, any update in this data will be reflected everywhere at the same time.
  • Screens: Screens will be on the receiver end of this project. Each screen uses local streams for its operations, and if global action is required, then accesses streams from managers using a singleton.

1.2. Motivation:

Zaiste proposed an idea in 2019 and created a plugin for such architecture. He named it “Sprinkel Architecture” and his plugin is called sprinkle which made our development easy to a certain level. But as of today, his plugin does not support new null safety features introduced in Dart 2.12.0. You can check more about his implementation here and can try his given sample with following command:

CODE: https://gist.github.com/velotiotech/023bbd24c8f112ae7b41e7b71ed9b922.js

1.3. Implementation:

We will be using the get plugin and rxdart plugins in combination to create our high performance architecture.

The Rxdart plugin will handle the stream creation and manipulation, whereas the get plugin can help us in dependency injection, route management, as well as state management.

2. Sample Project:

We will create a sample project to understand how to implement this architecture.

2.1. Create a project using following command:

CODE: https://gist.github.com/velotiotech/8c0f694a82eb2e37be65c787639d8da5.js  

2.2. Add these under dependencies of pubspec.yaml (and run command flutter pub get):

CODE: https://gist.github.com/velotiotech/1e09c87ca06e18d99efe537bb8847b99.js

2.3. Create 3 directories, constants, managers, and views, inside the lib directory:

2.4. First, we will start with a manager who will have streams & will increment the counter. Create dart file with name counter_manager.dart under managers directory:

CODE: https://gist.github.com/velotiotech/8ac0068aa1a04f88443325997aa6418a.js

2.5. With this, we have a working manager. Next, we’ll create a Supervisor who will create a singleton of all available managers. In our case, we’ll create a singleton of only one manager. Create a supervisor.dart file in the lib directory:

CODE: https://gist.github.com/velotiotech/3ce6451859a5d54943314a34460a5a7b.js

2.6. This application only has 1 screen, but it is a good practice to create constants related to routing, so let’s add route details. Create a dart file route_paths.dart:

CODE: https://gist.github.com/velotiotech/6e0b6abd2719e6980174e770cb068a4a.js

2.7. And route_pages.dart under constants directory:

CODE: https://gist.github.com/velotiotech/707c6e4026daf8d24a1f09e78f5c5b5e.js

2.8. Now, we have a routing constant that we can use. But do not have a CounterPage Class. But before creating this class, let’s update our main file:

CODE: https://gist.github.com/velotiotech/e2931f43d9bc6fda4cdb486374cd6403.js

2.9. Finally, add the file counter_page_controller.dart:

CODE: https://gist.github.com/velotiotech/413c9f3a173b060b03d794d21504906d.js

2.10. As well as our landing page  counter_page.dart:

CODE: https://gist.github.com/velotiotech/79ea2c811b70b0f49ad0e771adb2b235.js

2.11. The get plugin allows us to add 1 controller per screen by using the GetxController class. In this controller, we can do operations whose scope is limited to our screen. Here, CounterPageController provides CounterPage the singleton on CounterManger.

If everything is done as per the above commands, we will end up with the following tree structure:

2.12. Now we can test our project by running the following command:

CODE: https://gist.github.com/velotiotech/c9e1b5a8eaf030195699243b47df57f4.js

3. Additional Benefits:

3.1. Self Aware UI:

As all managers in our application are using streams to share data, whenever a screen changes managers’ data, the second screens with dependency on that data also update themselves in real-time. This will happen because of the listen() property of streams. 

3.2. Modularization:

We have separate managers for handling REST APIs, preferences, appStateInfo, etc. So, the modularization happens automatically. Plus UI logic gets separate from business logic as we are using getXController provided by the get plugin

3.3. Small rebuild footprint:

By default, Flutter rebuilds the whole widget tree for updating the UI but with the get and rxdart plugins, only the dependent widget refreshes itself.

4. Conclusion

We can achieve good performance of a Flutter app with an appropriate architecture as discussed in this blog. 

Did you like the blog? If yes, we're sure you'll also like to work with the people who write them - our best-in-class engineering team.

We're looking for talented developers who are passionate about new emerging technologies. If that's you, get in touch with us.

Explore current openings