avatarArathi Shankri

Summary

The website content discusses the navigation challenges and solutions when using the Provider package compared to the Flutter Bloc library for state management in a gaming app, specifically when the game timer expires.

Abstract

The article compares the implementation of state management using the Provider package with the Flutter Bloc library, highlighting the smooth transition the author experienced during the porting process except for two use cases, one of which is discussed in detail. The use case involves navigating to a different screen when the game timer expires. In the Flutter Bloc library, this is achieved using BlocListener to listen for a specific state and execute navigation without throwing exceptions. However, the Provider package lacks an equivalent to BlocListener, leading to errors when attempting to navigate during the build process. The author resolves this by using SchedulerBinding.instance.addPostFrameCallback to defer navigation until after the current build is complete, a solution confirmed by the Provider package's author, Remi Rousselet, who also mentions an ongoing proposal to address this issue.

Opinions

  • The author finds the Provider package easier to use than Flutter Bloc due to fewer required classes.
  • The BlocListener in Flutter Bloc is seen as a clean and effective way to handle navigation without disrupting the build process.
  • The author was initially concerned about the lack of a BlocListener equivalent in Provider but found a workable solution through community resources like Stack Overflow and direct communication with the Provider package's author.
  • The author endorses the SchedulerBinding solution as a reliable method to handle navigation in Provider without causing widget build conflicts.
  • The author encourages following the open issue on GitHub for updates on a more integrated solution for navigation in Provider.
  • The author is optimistic about the future improvements in the Provider library, based on Remi Rousselet's proposal to solve the navigation issue.

Navigation in Provider

Material Bottom Sheet pic from https://material.io/components/sheets-bottom/#

As I work steadily to complete my gaming app, it was exciting to learn the differences between implementing state management using the Provider package Vs Flutter Bloc. Similar to Flutter Bloc library, it has been quite easy to implement this pattern and I have come to realize that there are quite a few extra classes you write in Bloc when compared to Provider.

Though much of my porting has been very smooth, currently there are two important use cases that I want to share. This article is one such use case and the second one is coming soon.

USE CASE

There are many such instances in your app when you would like to navigate the user to a different route/screen using any of these techniques.

  • Navigator.pushNamed, showDialog, showModalBottomSheet or Scaffold.showSnackBar

In my gaming app, when the game timer expires, I am navigating the user to a screen with a message to restart the game.

Bloc Implementation

In Flutter Bloc library, the above use case is accomplished using BlocListener and wrapping your BlocBuilder with BlocListener.

  • While the BlocBuilder builds and returns a widget; thus the reason you won’t be able to navigate from the builder.
  • BlocListener, on the other hand, takes precedence and listens to a particular state. When your Bloc emits that state, the piece of code within the listener executes. The program control doesn’t proceed down to builder and you won’t see the infamous exception,

“Build Functions must never return null.”

Below is the snippet of the code in action; you can also refer to Felix Angelov’s excellent tutorial.

Notice BlocListener’s child is BlocBuilder, line 15 and we are checking for the state on line 8 and navigating.

Provider Equivalent

In the Provider package, there is nothing similar to the BlocListener class.

So, within your ChangeNotifierProvider/Consumer widget, if you try navigating using any of the above techniques, you would see the below error message;

“This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets.”

The above error essentially means that you are trying to rebuild multiple widgets at/around the same time.

So, when the timer expires and the value goes to 0; the widget displaying the timer value that is notified on every value change is rebuilding the widget painting the current value 0. Around the same time, the ChangeNotifier would also be triggered and widget trying to display the timer expired message is also building to display. Hence, the conflict.

The only way we can make the navigation work is by using

SchedulerBinding.instance.addPostFrameCallback and registering your snackbar or bottomsheet as a callback, as shown in the code below.

Instead of my custom XShow class that displays the bottom modal sheet, you would embed your code to do the same within the addPostFrameCallback(()){}

The above code waits for the current build to complete before executing the callback code. Hence, you won’t get the overlay widget error.

Conclusion

It was a little worrying not to right away find an equivalent of BlocListener in the Provider library. But after some googling and thanks to StackOverFlow, I found the above SchedulerBinding solution that works perfectly without any uncertainty. I also emailed Remi Rousselet, the author of Provider package to ensure that this is the only, right way to do it.

As per Remi, he currently has a proposal that would solve this and has opened an issue. To receive updates, you could follow or subscribe to the issue as well, https://github.com/flutter/flutter/issues/50961

I hope my article helps you with your navigation questions while using the Provider package!

Happy Thinking!

Arathi

Flutter
Flutter Widget
Flutter Provider
Flutter State Management
Flutter Bloc
Recommended from ReadMedium