Provider Lifecycles
The content of this page may be outdated.
It will be updated in the future, but for now you may want to refer to the content
in the top of the sidebar instead (introduction/essentials/case-studies/...)
When does my Provider get created and disposed?
The states that all different types of providers can go through are the same:
- Uninitialized
- Alive
- Paused
- Disposed
Disposed / Uninitialized
An Uninitialized or Disposed provider does not take up any memory since its state is not initialized. Essentially it is just a definition of how to create the provider's state when you need it. It will stay that way until an Alive provider or a WidgetRef from the UI reads, watches, or listens to it.
Creating -> Alive
When an Uninitialized provider is read, listened to or watched it's state will be created.
During creation your provider's build function will be run.
Any providers that you read or watch using the ref
exposed by the callback will be created as needed and their state will be retrieved.
If there are any circular dependencies during this creation process Riverpod will throw an error. The best way to fix this error is to redesign your dependencies to have a uni-directional dataflow.
The provider's state is stored in a ProviderContainer. In a Flutter app this container is in a ProviderScope widget.
As such, even though the definition of how to create the state (the provider) is global, the state is actually local, and can be different in different portions of your UI using nested ProviderScope widgets and overrides.
This is very similar to how flutter widgets work. You only pay for the definition once, but can reuse the state in different parts of the tree as needed.
Alive
When your provider is Alive, changes to its state will cause dependent providers and/or the dependent UI to rebuild.
From the other perspective, as a reactive framework, you can watch other providers to have the provider recreate itself whenever one of it's dependencies changes.
If you need to have some long-lived state that depends on other state you can use Ref's listen method to subscribe for changes on another provider without causing a rebuild of the provider.
If you need to use the state from another provider in a side-effect, you can use Ref's [read] method to obtain the current state from another provider.
Typically when constructing a StateNotifier or ChangeNotifier class you should pass in the ref
to allow the Notifier to obtain the current value of dependencies as needed. By using the new Notifier and AsyncNotifier classes from Riverpod 2.0, the ref is already available as an instance member of the class.
Alive -> Paused
When an Alive provider is no longer listened to by other providers or the UI, it goes into a Paused state. This means that it no longer will react to changes on providers it is listening to. This is an optimization, as if you are not listening to the provider, there is no need to keep it alive. Every provider not being used will be returned to a Paused state, reducing the computational burden of your app.
If you need to keep a provider alive for side-effects, make sure to listen to it in an appropriate place in the UI where it should be kept alive.
If you need to perform some action when a provider is paused use the ref's onCancel method to register callbacks.
If you need to perform some action when a provider resumes to an Alive state from a paused state, use the ref's onResume method to register callbacks.
If you want the state to be disposed, so that in addition to taking no computational resources, it also disposes of the memory of the state, use the .autoDispose
modifier on your provider definition.
This will cause it to transition to a Disposed state instead of Paused when it is no longer being used.
Alive -> Disposing
There are a few reasons for a provider to be disposed.
- When defined using the
.autoDispose
modifier and no longer being watched by the UI or another provider - When the provider is being manually refreshed or invalidated
- When the provider is being recreated due to one of it's watched dependencies changing
Refreshing causes the provider to immediately go through the creation process again, whereas invalidating causes the next read / watch of the provider to cause the provider to be rebuilt.
Performing actions before the state destruction
If you need to perform some action when a provider is disposed, use the ref's onDispose method to register callbacks.
The following example uses onDispose to close a StreamController:
Stream<int> example(Ref ref) {
final streamController = StreamController<int>();
ref.onDispose(() {
// Closes the StreamController when the state of this provider is destroyed.
streamController.close();
});
return streamController.stream;
}
Depending on the provider used, it may already take care of the clean-up process.
For example, StateNotifierProvider will call the dispose
method of the returned StateNotifier.