rrousselgit / provider Goto Github PK
View Code? Open in Web Editor NEWInheritedWidgets, but simple
Home Page: https://pub.dev/packages/provider
License: MIT License
InheritedWidgets, but simple
Home Page: https://pub.dev/packages/provider
License: MIT License
I used provider in my project and I fond a strange trigger mechanism.
Widget build(BuildContext context) {
final notifer = Provider.of<Notifier>(context);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
When I push a new page, I noticed that the first page's provider was touched off, but no notifyListeners was called. And when I pop the second page, the first page's provider was touched off again, still no notifyListeners was called. If I removed the
final notifer = Provider.of<Notifier>(context);
then the Widget will not refresh every time I push or pop.
When I have small screen I would like to define them like this:
Widget build(context) {
return StatefulProvider<MyBloc>(
valueBuilder: (context, old) => old ?? MyBloc(),
onDispose: (context, bloc) => bloc.dispose(),
builder: (context, bloc) => StreamBuilder<String>(
stream: bloc.stream,
builder: (context, snapshot) => Text(snapshot.data),
)
),
}
If we want to achieve this currently we need to extract the screen into another widget, and retrieve the bloc on the build method. It can be better IMHO
Hi,
Does provider support providing dependency asynchronously ?
Something similar to Dagger Producers on Java (Android).
Provider would heavily benefit from showing the current value in the widget inspector
Let's do this.
As I was thinking of using Provider + BLoC. Usually with Inherited widget what is possible is to provide a bloc specific to the route / sub child widgets.
When I tried the same with Provider it fails to recognize the Bloc?
But same works in case If I initiate bloc from outside of MaterialApp.
void main() {
runApp(
Provider<DevicesBloc>(
builder: (ctx) => DevicesBloc(),
child: MaterialApp(
title: 'WaterLeveller',
home: DevicesListScreen(),
),
),
);
}
class DevicesListScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Color(0xFF448C33),
title: const Text("Water Leveler"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => AddDeviceScreen()));
},
)
],
),
body: Container(
child: ListView(
children: <Widget>[
GestureDetector(
child: Padding(
padding: EdgeInsets.all(30),
child: Text("List 1"),
),
)
],
),
),
);
}
}
Those are the parent widgets, and the below one is child widget, In which I have a button "Add" on press, I would like to call a function inside the DevicesBloc, which works in this case.
class AddDeviceScreen extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Add Device"),
),
body: Container(
margin: EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(
hintText: "Device Name"
),
style: TextStyle(
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0,14.0,0,0),
child: RaisedButton(
onPressed: (){
Provider.of<DevicesBloc>(context).addDevice();
},
child: Text("Add"),
),
)
],
),
),
);
}
}
But same won't work in case I move the bloc provide inside DeviceListScreen like this.
void main() {
runApp(
MaterialApp(
title: 'WaterLeveller',
home: DevicesListScreen(),
),
);
}
class DevicesListScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Provider<DevicesBloc>(
builder: (ctx) => DevicesBloc(),
child: Scaffold(
appBar: AppBar(
backgroundColor: Color(0xFF448C33),
title: const Text("Water Leveler"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => AddDeviceScreen()));
},
)
],
),
body: Container(
child: ListView(
children: <Widget>[
GestureDetector(
child: Padding(
padding: EdgeInsets.all(30),
child: Text("List 1"),
),
)
],
),
),
),
);
}
}
This throws this exception.
I/flutter (18418): ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
I/flutter (18418): The following ProviderNotFoundError was thrown while handling a gesture:
I/flutter (18418): Error: Could not find the correct Provider<DevicesBloc> above this AddDeviceScreen Widget
I/flutter (18418):
I/flutter (18418): To fix, please:
I/flutter (18418):
I/flutter (18418): * Ensure the Provider<DevicesBloc> is an ancestor to this AddDeviceScreen Widget
I/flutter (18418): * Provide types to Provider<DevicesBloc>
I/flutter (18418): * Provide types to Consumer<DevicesBloc>
I/flutter (18418): * Provide types to Provider.of<DevicesBloc>()
I/flutter (18418): * Always use package imports. Ex: `import 'package:my_app/my_code.dart';
I/flutter (18418): * Ensure the correct `context` is being used.
I/flutter (18418):
I/flutter (18418): If none of these solutions work, please file a bug at:
I/flutter (18418): https://github.com/rrousselGit/provider/issues
Which in my opinion should be possible ? Or is it something should not be done?
There are a few inconsistencies among the public API
StreamProvider.builder
from the default constructor requests a StreamController
instead of a stream. It'd be more logical for the default constructor to request a Stream
, and have a named constructor or another class for the StreamController
.
XXProvider.value
have inconsistencies in the name used for the value. ChangeNotifierProvider
requests a notifier
, Provider
requests a value
, ValueListenableProvider
requests a valueListenable
. But they probably should all be named value
.
Not an immediate issue, but ProxyProvider.custom
has a weird naming issue. It takes both a builder
and a providerBuilder
argument. Maybe we should globally rename builder
to something better (valueBuilder
like it originally was?)
These are minor changes but requires a breaking change.
I want to have the ability to provide multiple implementations of one interface (or multiple instances of the same class) and to consume the one I need depending on the name.
Something like this to provide
MultiProvider(
providers: [
Provider.value(value: "Object one", name: "oneone"),
Provider.value(value: "Object two", name: "twotwo"),
],
.......
)
...and to consume
Provider.of(context, name: "oneone")
Provider.of(context, name: "twotwo")
How can achieve this?
Thanks :)
In the example provided on the pub page, I get an error No Directionality widget found. RichText widgets require a Directionality widget ancestor.
I think the example may need to be updated, or some clarification made.
To reproduce I am using VS Code with the latest flutter and dart versions. I cut and pasted the example code into the editor and compiled to get the error.
Hello, nice library 😀.
can you explain me please what is the difference.
Provider.of<SomeClass>(context, listen: true)
Provider.of<SoomeClass>(context, listen: false)
I noticed that I can use in initState()
of StatefulWidget
when is false
, and can't use when is true
, but really I don't know why :(
Thanks
Good Day Remi,
Could you please explain how to use the provider in initState, i have tried many way and all have failed except doing below
# Future.delayed(Duration.zero, () { Provider.of<PrincipalProvider>(context, listen: false).fetchPrincipals(); });
Is there a better way to implement it?
Also, the code worked perfectly in the scoped_model
ScopedModel.of<PrincipalProvider>(context).fetchPrincipals();
I want to fully embrace the provider model, but I just need some clarity.
Consumer
is cool. But we may want more than one value.
And nesting consumers is not cool.
Let's do consumers with multiple arguments
Consumer2(
builder: (BuildContext context, int foo, String bar) => Container(),
);
Is the example code show by @brianegan in "Merge provider and scoped_model"
brianegan/scoped_model#61 the "correct" way to use this provider?
Simple examples of the existing providers would help a lot for users of "scoped_model". Your only example of the 'simple' provider seems to me to be the least useful as it isn't 'reactive' (if I'm reading the docs correctly)
thanks for all your work!
Hi @rrousselGit ,
Suppose I already have a class A extends B, in order to use the ChangeNotifierProvider, I have to mixin the ChangeNotifier. Now, in my A.dispose, I expect the super.dispose to B.dispose, but it ends up with the ChangeNotifier.dispose. That will somehow ruin my logic.
May I what is the alternative to the ChangeNotifierProvider if the class is not extends/mixin from ChangeNotifier?
Thanks in advance.
Hi, this probably isn't a bug, but I don't understand what is going on here.
I get thouse 2 errors:
- Could not find the correct Provider<SecondPageBloc> above this ChangeStringWithButton Widget
- There are multiple heroes that share the same tag within a subtree.
This is my MultiProvider at the Myapp() main page:
home: MultiProvider(
providers: [
Provider<CounterBloc>(
value: CounterBloc(),
),
Provider<UserBloc>(
value: UserBloc(),
),
Provider<SecondPageBloc>(
value: SecondPageBloc(),
),
],
child: BlocCounterPage(), // the main page
),
depending on the child ^ which i am using in the MultiProvider that widget is working but if I navigate to another page with the drawer I get the error mentioned above
The Navigation from the Drawer:
Divider(height: 2.0, color: Colors.blue,),
ListTile(
leading: Icon(Icons.text_fields),
title: Text('Change Text with button'),
onTap: () {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (BuildContext context) {
return ChangeStringWithButton();
}));
}
),
This is a simple counter bloc
import 'dart:async';
import 'package:rxdart/rxdart.dart';
import 'package:simple_bloc/api/db_api.dart';
import 'package:simple_bloc/models/user.dart';
class UserBloc {
User _user;
final _userController = BehaviorSubject<User>();
Stream<User> get outUser => _userController.stream;
UserBloc(){
init();
}
void init() async {
_user = await api.getUser();
_userController.add(_user);
}
void updateUser(User user){
_user = user;
_userController.add(_user);
}
}
Another thing If I use pushReplacment to navigate I get a big error:
Could not find the correct Provider<SecondPageBloc> above this ChangeStringWithButton Widget
Hello if I want to use Provider.of... in multiples routes, the Provider widget must be a parent of material app? Or I can create de Provider widget in any route(no material app widget) and routes pushed by this widget can use Provider.of... ?
Thanks
The description under "About" in https://pub.dev/packages/provider has small mistakes:
An helper to easily exposes a value using InheritedWidget without having to write one.
Cheers.
Similar to:
reactiveui/ReactiveUI#979
PrismLibrary/Prism#1016
brianegan/flutter_redux#86
felangel/bloc#139
If anyone is using the library then please give your input.
Use the following template:
If available on stores
iOS:
Android:
If open source
Source Code:
Your opinion
Version: ?
Years of experience: ?
Good: ?
Bad: ?
Thank you very much!
From experience looking at larger Flutter applications, it is relatively common to have some dependency between providers.
For example, we may have a Provider<Configuration>
and a Provider<AuthentificationService>
where the latter depends on the former.
But that's currently not something we can represent purely using provider
package. Our only solution right now is to somehow eject provider
and handle everything ourselves like so:
Configuration configuration;
Widget build(BuildContext context) {
return MultiProvider(
providers: [
Provider.value(value: configuration),
Provider(builder: (_) => AuthentificationService(configuration)),
],
child: MaterialApp(...),
);
}
That's not good.
It reintroduces the ability to make a circular object graph & forget to update/dispose of an object.
We're loosing all the fancy securities that using widgets for DI brings.
The discussion on #44 made me realize that an advanced Consumer
may be able to solve this issue.
Naively we could think of doing:
MultiProvider(
providers: [
Provider<Foo>(builder: (_) => Foo()),
Consumer<Foo>(builder: (context, foo, child) {
final bar = Bar(foo);
return Provider<Bar>.value(value: bar, child: child);
}),
].
child: MaterialApp(...),
);
... The problem is that we're doing final bar = Bar(foo);
inside the build method of Consumer
.
That's not good either – we may have memory leaks.
But that's something we can fix using a more advanced Consumer
, which I'll call ProxyProvider
for now.
The idea behind ProxyProvider
is that it would work similarly to the default constructor of Provider
, but also like Consumer
as it would read values from other providers and pass them to the builder
.
The same example using ProxyProvider
would be:
MultiProvider(
providers: [
Provider<Foo>(builder: (_) => Foo()),
ProxyProvider<Foo, Bar>(builder: (context, Foo foo, Bar previousBar) {
return Bar(foo);
}),
].
child: MaterialApp(...),
);
In that example, the builder
of ProxyProvider
would be called on the first build; or whenever Foo
changes.
Interesting pattern. Do you have a suggestion for how to use a Bloc that requires a parameter?
I have been using another inherited widget that I use to retrieve the parameter and inject it into Bloc. Is there a convenient way to use this pattern to manage such a case?
Also, the inherited widget apparently does not have a dispose. Does this not result in a possible memory leak if used in stateless widgets (which also does not have a dispose) and in other cases? What is the best way to dispose of Bloc resources?
Here is a project that uses a stateful widget as a Bloc provider that disposes Bloc resources:
https://github.com/boeledi/Streams-Block-Reactive-Programming-in-Flutter/blob/master/lib/blocs/bloc_provider.dart
Here is the article that discusses it:
https://www.didierboelens.com/2018/08/reactive-programming---streams---bloc/
What is the recommended method to manage memory, or am I missing something?
It will be great if we can have an example of every available provider to start with. Its easier for a guy like me who is just starting with flutter and provider to understand it better.
I'm making fintech app with flutter and i was managed login workflow with this library but i have three listview (datas came from API , im not sure how big it is ) such as ; Income,Outcome and AllOfThem.
I know ListView.Builder and scrollController but sometimes i need to add some items to list and call the API for adding items also change the UI screen.
Can i manage this , using your library ?
If answer is yes , How ? If answer is no , Why ?
class TestPage extends StatelessWidget {
@override
Widget build(BuildContext context) => HookProvider(
hook: () => useState(0),
child: Consumer<ValueNotifier<int>>(
builder: (context, index) => Scaffold(
appBar: AppBar(
actions: <Widget>[
FlatButton(
child: Text("Second screen"),
onPressed: () => showDialog(
context: context,
builder: (context) => HookProvider(
hook: () => index,
child: Consumer<ValueNotifier<int>>(
builder: (context, index) => Scaffold(
appBar: AppBar(
title: Text("Second screen"),
),
body: Center(
child: FlatButton(
child:
Text("Index: ${index.value}"),
onPressed: () => index.value++,
),
),
),
),
updateShouldNotify: (_, __) => true,
)),
)
],
),
body: Center(
child: FlatButton(
child: Text("Index: ${index.value}"),
onPressed: () => index.value++,
),
),
),
),
updateShouldNotify: (_, __) => true,
);
}
What i'm trying to do is change a hook's value from within another screen, and it works... kinda, the value is updated but the second screen's widget is not rebuilt for some reason (if you go back you can see the new value). So is it a bug or this behavior should be expected?
What would be the best pattern for breaking a large Provider into two Providers, but still have one of them listen to changes on the other. For example I want to have two Providers, one named User and one named Favorites. If the User changes then the Favorites needs to reload and notify its own listeners.
I think this is a bug
It should working but it say could not find the correct Provider
I try to change to this too still not work
class _LoginViewState extends State<LoginView> {
final TextEditingController _controller = TextEditingController();
@override
Widget build(BuildContext context) {
return Column(
children: <Widget> [
StreamBuilder<Chat>(
stream: Provider.of<Socketio>(context).streamChat,
builder: (context, snapshot) {
return Text(snapshot.data?.toString() ?? 'Foo');
},
),
BaseView<LoginModel>(
builder: (context, model, child) => Scaffold(
backgroundColor: backgroundColor,
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
LoginHeader(
validationMessage: model.errorMessage,
controller: _controller),
model.state == ViewState.Busy
? CircularProgressIndicator()
: FlatButton(
color: Colors.white,
child: Text(
'Login',
style: TextStyle(color: Colors.black),
),
onPressed: () async {
var loginSuccess = await model.login(_controller.text);
// await model.login(_controller.text);
if(loginSuccess){
Navigator.pushNamed(context, '/');
}
},
)
],),
),
)
]
);
}
this is where Im declare the provider in main.dart
void main() {
setupLocator();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider<User>(
initialData: User.initial(),
builder: (context) => locator<AuthenticationService>().userController,
),
StreamProvider<Chat>(
initialData: Chat.initial(),
builder: (context) => locator<Socketio>().chatController,
),
],
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(),
initialRoute: '/login',
onGenerateRoute: Router.generateRoute,
),
);
}
}
Hooks allow some very powerful provider:
HookProvider<MyBloc>(
value: () {
final bloc = useMemoized(() => MyBloc());
useEffect(() => bloc.dipose, [bloc]);
return bloc;
},
child: Container();
);
See https://docs.flutter.io/flutter/widgets/AnimatedBuilder/AnimatedBuilder.html
Otherwise you can end up in performance inefficiencies where a top-part of a subtree depends on the thing dependency injected but the rest of the tree doesn't. You'd end up constantly rebuilding that whole subtree.
Letting Consumer have a child instance and letting its builder have BuildContext context, Widget child, T value
can let the builder stop the tree rebuild traversal by putting the same child instance back in the returned widget subtree.
such as: in my app, i need to request some configs from server(maybe several apis), but this function(which combined these apis, but these child functions are in different providers/states) should be called exactly only once. so what's the correct way to do with it? because of build and didChangeDependencies function may called multi times, so i can't call init in these function, but in initState, the 'listen' parameter can only be 'false' and this will throw exception if i call multi different child function.
Examle:
i have A,B states
in A:
class AStates with ChangeNotifier {
...
appInit() async{
...
childInitFunc1();
childInitFunc2();
childInitFunc3();
// if i call initB it will throw exception whatever listen is true or false
Provider.of(context,listen:false).initB();
}
...
}
in B:
class BStates with ChangeNotifier {
...
initB() async{
...
}
...
}
in index.dart:
class Test extends StatefulWidget {
@OverRide
_TestState createState() => _TestState();
}
class _TestState extends State with WidgetsBindingObserver {
@OverRide
void initState() {
//
// init here and if listen is true, it will throw exception
//
Provider.of(context, listen:false).appInit(state);
WidgetsBinding.instance.addObserver(this);
super.initState();
}
@OverRide
void didChangeDependencies() {
// can't init here
super.didChangeDependencies();
}
@OverRide
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@OverRide
void didChangeAppLifecycleState(AppLifecycleState state) {
Provider.of(context).changeAppLifecycleState(state);
super.didChangeAppLifecycleState(state);
}
@OverRide
Widget build(BuildContext context) {
// can't init here
return Container();
}
}
so what's wrong with my code? and what should i do correctly ?
First of all, your StatefulProvider
is a really neat method to deal with disposing blocs that live in inherited widgets. I'm certainly going to use this pattern! In the following I'm assuming it's used specifically to serve blocs.
I want to share a concern: The implementation allows to reuse a previous
value by passing it to valueBuilder
. I'm not sure if this actually does what I guess it's supposed to do, and worse, if it might even impose the risk of unwanted/dangerous side effects.
If valueBuilder
was expected to be called multiple times on the same widget (the provider), and creation of the value is expensive, then I would see a clear benefit in re-using an old value. But does that actually happen? valueBuilder
is called during initState
, in which case previous
will obviously be null
for a new provider instance and a new state. It's also called during didUpdateWidget
, but that should happen only if the provider widget itself changed. So according to my understanding, the original provider widget will never actually make use of this reuse mechanism. But then what's the point? Maybe to share a value between multiple different Providers? That would seem very fragile to me, given Flutter's particular update handling of Widgets, Elements, and States.
Say there's Provider<Bloc> providerA
that generates a _StatefulProviderState<Bloc>
with _value = blocA
. Now, under very specific circumstances providerA
gets replaced by a new Provider<Bloc> providerB
(same type, same key). Both providerA
and providerB
have the same valueProvider: (_, bloc) => bloc ?? Bloc()
. Since Flutter sees the chance to re-use the already existing _StatefulProviderState<Bloc>
, it wires it to providerB
. Now, providerB
works with blocA
instead of a fresh instance of Bloc
. As the package user, I would not expect this behavior.
Clearly I might be overlooking an important detail or my assumptions could be wrong – could you please explain why you think this specific implementation of re-using an old value is beneficial, and if my concern regarding side effects is unwarranted?
my pubspec.yaml has
sdk: ">=2.1.0 <3.0.0"
If I use 2.3.0 features I get
The for, if and spread elements were not supported until version 2.2.2, but this code is required to be able to run on earlier versions.
Try updating the SDK constraints.
if I change the pubspec.yaml to 2.3.0 as the lower bound then flutter get spits back
Running "flutter packages get" in flutter_provider...
The current Dart SDK version is 2.3.0-dev.0.5.flutter-a1668566e5.
Because flutter_provider requires SDK version >=2.3.0 <3.0.0, version solving failed.
pub get failed (1)
exit code 1
here is my flutter --version
Flutter 1.5.4-hotfix.2 • channel beta • https://github.com/flutter/flutter.git
Framework • revision 7a4c33425d (2 weeks ago) • 2019-04-29 11:05:24 -0700
Engine • revision 52c7a1e849
Tools • Dart 2.3.0 (build 2.3.0-dev.0.5 a1668566e5)
StatefulProvider
Version 2.0.0 merges StatefulProvider
into Provider
and leads to a nicer API.
However, with this change some use cases are no longer supported.
For example, I have an email & password sign in form where the user can switch between 3 different modes: sign in, register, reset password:
The logic for updating the state is handled inside a bloc, and I use a StreamBuilder
to update the UI.
When the system keyboard appears, the entire page is rebuilt.
And with StatefulProvider
everything works fine, because the bloc is not created again when the keyboard appears (this is expected, as a StatefulWidget
's state is preserved when the parent is rebuilt).
However, this doesn't work with provider: 2.0.0
, because when the keyboard appears the entire bloc is rebuilt and the UI is rebuilt with the initial state rather than the previous state.
This leads to some unexpected behaviour where the form state changes when I start typing on a text field:
This is just an example, but I have a more complex app with a lot of nested StatefulProvider
s. And I can see how rebuilds in parent widgets would cause a lot of problems, as my blocs would be re-created and their state reset.
Ultimately the problem is that we need a Provider
that inherits from StatefulWidget
rather than InheritedWidget
, so that the value/bloc is created in initState()
and the state is preserved when a parent widget is rebuilt.
The app works like this:
It has a Counter with ChangeNotifier and a ThemeSwitch also with ChangeNotifier
if number > 5 it changes to dark.
Consumer2 is used ( the logic for switching is made inside Consumer2).
I have this question too: How can I have access to Counter value inside the ThemeSwitch class to make the logic there.
The error happens when one of them is rebuilding the same descendants when the other is rebuilding at the same time.
Error:
Exception has occurred. FlutterError (setState() or markNeedsBuild() called during build. This ChangeNotifierProvider<ThemeSwitch> widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase. The widget on which setState() or markNeedsBuild() was called was: ChangeNotifierProvider<ThemeSwitch>(state: _ListenableProviderState<ThemeSwitch>#e36d8) The widget which was currently being built when the offending call was made was: Consumer2<ThemeSwitch, Counter>(dirty, dependencies: [_Provider<ThemeSwitch>, _Provider<Counter>]))
Files:
// main.dart
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
import 'package:provider_tutorial/counter.dart';
import 'package:provider_tutorial/theme_switch.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return
// inject providers
MultiProvider(
providers: [
ChangeNotifierProvider<Counter>(builder: (context) => Counter(0)),
ChangeNotifierProvider<ThemeSwitch>(
builder: (context) => ThemeSwitch(ThemeState.light),
),
],
// 2 Consumers
child: Consumer2<ThemeSwitch, Counter>(
builder: (context, themeSwitch, counter, widget) {
themeSwitch.themeState =
(counter.value > 5) ? ThemeState.dark : ThemeState.light;
return MaterialApp(
title: 'Flutter Demo',
theme: themeSwitch.theme,
home: MyHomePage(),
);
},
),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counterProvider = Provider.of<Counter>(context);
print(counterProvider.value.toString());
return Scaffold(
appBar: AppBar(
title: Text('Providers Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'If Number > 5 theme is dark:',
),
Consumer<Counter>(
builder: (context, counter, widget) {
return Text(
'${counter.value}',
style: Theme.of(context).textTheme.display1,
);
},
),
],
),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FloatingActionButton(
onPressed: () {
counterProvider.increment();
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
SizedBox(
height: 20,
),
FloatingActionButton(
onPressed: () {
counterProvider.decrement();
},
tooltip: 'Decrement',
backgroundColor: Colors.red,
child: Icon(Icons.remove),
),
],
),
);
}
}
// theme_switch.dart
import 'package:flutter/material.dart';
enum ThemeState { light, dark }
class ThemeSwitch with ChangeNotifier {
ThemeSwitch(this._themeState);
ThemeState _themeState;
ThemeData _theme;
ThemeState get themeState => _themeState;
ThemeData get theme => _theme;
set themeState(ThemeState themeState) {
_themeState = themeState;
if (_themeState == ThemeState.light) {
_theme = ThemeData.light();
} else {
_theme = ThemeData.dark();
}
notifyListeners();
print("theme state changed");
}
}
// counter.dart
import 'package:flutter/foundation.dart';
class Counter with ChangeNotifier {
Counter(this._value);
int _value = 0;
int get value => _value;
set value(int value) {
_value = value;
notifyListeners();
}
increment() {
value++;
}
decrement() {
value--;
}
}
@jiaeri said:
Do you think ListenableProvider is needed? It does add some complexity, where it might be cleaner on the consumer side
A ListenableConsumer can just use an ordinary provider, and look like this:
class ListenableConsumer extends StatelessWidget {
final Widget Function(BuildContext context, T value, Widget child) builder;
ListenableConsumer({Key key, @required this.builder}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer(
builder: (context, value) =>
AnimatedBuilder(animation: value, builder: builder));
}
}
The dispose method is not called
I'm not sure provider
lib is able to do this, but let see my case:
build()
method to update its UI but no place to handle Login success action.Could you please share with me your experience in similar case? Thanks.
A shorthand to wrapping a HookProvider
into a StreamBuilder
or equivalent.
I really like this package. Especially the straightforward naming (coming from scoped_model
)
Would it be possible to rename SingleChildCloneableWidget
to something like BaseProvider
or AbstractProvider
to make it more readable?
I suppose most users don't ever use this class but my app is quite complex and I find it very useful...
ChangeNotifier is O(N^2) for notify listeners. It has to make a copy of the list of listeners, iterate that copy, and during the iteration do another iteration of the original list to see if the listener is still registered.
This seems particularly troubling for the MultiProvider case (which would get to O(N^3)), but could be a problem anywhere you have lots of widgets listening to the same provider.
A possible optimization here is to see if we can stuff the callbacks into a set or map, e.g. by having addListener
and removeListener
(or the equivalent wrappers of them) using integer handles instead of the actual callback - or just using a set if that works for callbacks (I'm not sure how hashCode
is handled on a var that is a closure), which should get this back to O(N).
Some objets like Bloc have custom dispose behavior. We should provide a way to clean things properly with StatefulProvider
For unknown reasons, codecov.io says that /lib/src/adaptive_widget_builder.dart
is only partially covered by tests when it has in fact 100% coverage.
I know ChangeNotifierProvider
automatically disposes of the provided value itself.
But I hit a case when I'm creating a Timer
that modifies the ChangeNotifier
during its lifetime. (That's obviously just a sample, and it's too synthetic and generally bad.) In this case, it would be nice to be able to dispose of the Timer with the ChangeNotifier.
I hypothesize that something similar will quite often happen in the real world as well. For example, you have a ChangeNotifier that you use as a "view model", and network events can change it. Now, you could put the network logic into the ChangeNotifier, but sometimes it's nicer to have it as a separate class. For example, you could have:
ChangeNotifierProvider(
builder: (context) {
var network = MyNetworkConnection();
return MyModel(network);
}
dispose: ???,
child: ...
}
Welp, I just realized that you can't do that, since the dispose callback wouldn't give you the MyNetworkConnection
object.
So, never mind. This is probably another use case for ProxyProvider, where I provide the MyNetworkConnection
to the ChangeNotifierProvider<MyModel>
.
Feel free to close this immediately. Just wanted to have this around for future reference.
Hi
when loading data from firestore or api the red screen with size , length error appear for while before show items so i want to add circularprogressindicator while loading data?
i am using stream provider with firestore
Can we get repackeged version of provider library for Flutter Web?
Flutter Web is using widgets from package:flutter_web instead of package:flutter.
One thing I don't get it:
An app with master and detail views.
I want to supply a DAO class for each view.
Should I use a Multiprovider right after main() or should I use individual Providers in the views class?
I want to instatiate the classes only when the view is loaded. My question is do they get instantiated already if I put it on the top of the app or do they have like lazy instantiation
Originally posted by @peekpt in #77 (comment)
I wonder if Inherited widget is more performant then using Singleton
Hello,
I am learning provider way & found difficulty in lifting state up. I have three screens,
I lift state up in item's listing screen & use provider there. Which is working perfectly fine. But now I need to access that same provider in create & edit screen.
One thing I can do is, initiate provider in MaterialApp() declaration, but problem is I have another 4-5 providers for other parts of the application, & it's not feeling good to put all providers in MaterialApp().
So, what I have done is, I am passing itemProvider of listing screen to create & edit screen in Navigator as argument like this.
Navigator.pushNamed( context, "item.create", arguments: { 'itemProvider': Provider.of<ItemProvider>(context) }, )
My question is, is it a good thing to do or is there any other way to do this?
I'm just trying out Provider for the first time, and struggling to find the equivalent of State
's mounted
property.
I have a class that mixes in ChangeNotifier
. In one of its methods it awaits on a network call, then notifyListeners()
with the result of that network call.
If the user has navigated away while the network call is pending, I get an error
E/flutter (27530): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: A XXX was used after being disposed.
E/flutter (27530): Once you have called dispose() on a XXX, it can no longer be used.
E/flutter (27530): #0 XXX&Object&ChangeNotifier._debugAssertNotDisposed.<anonymous closure> (package:flutter/src/foundation/change_notifier.dart:105:9)
E/flutter (27530): #1 XXX&Object&ChangeNotifier._debugAssertNotDisposed (package:flutter/src/foundation/change_notifier.dart:111:6)
E/flutter (27530): #2 XXX&Object&ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:200:12)
In the basic StatefulWidget
scenario, I would just check if (mounted)
before calling setState
. Is there an equivalent for ChangeNotifier
?
Thanks!
Hi , i have some issue or some miss understanding in here. I'm trying to authentication flow.When i click the login button without delaye status is not changing but if i add future delaye in signIn method status flow like this ;
UnAuthenticated => Authenticating => Authenticated
without future delayed ;
UnAuthenticated ==> Authenticated
PS:I have dummy repository for authentication and it has future delayed itself.
here is my sample of project ;
Thank you ,
I did this simple sketch example, I'm no expert, but I think if the dev team adds diagrams to documentation will help a lot people that are starting to learn this Plugin.
There's information missing like how the values behave, how they update, etc...
With all this providers and ways to reach the provided values it is start to get confusing.
Having a way to filter updates at the consumer level may be useful to fine-grain builds.
For example, if we have a ChangeNotifier
model with multiples properties,notifyListeners
would be called each time a value of a property changed. If we have a Consumer
for that model that only depends on one of the properties, it is updated even when an other property changes.
We could have a bool shouldBuild(T previousValue, T newValue)
argument for Consumer
for that purpose.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.