Reputation: 341
so I have aConsumer<NotificationProvider>
and in its builder function a StreamProvider<List<Item>>
.
Please note that the latter widget builds perfectly on its initial load.
NotificationProvider
contains a list of notifications from Firebase Cloud Messaging, ergo when I receive a notification, I push something into the class' Listand then call
notifyListeners()`.
Please also note that my NotificationProvider is doing a good job because I have a counter at my AppBar
and it's updating whenever I receive one.
Now on to the meat and potato.
I'm trying to rebuild the StreamProvider whenever NotificationProvider.addAlert()
is called. But somehow it's not working?
I also added updateShouldNotify: (prev, next) => true,
but it didn't help one bit.
Please help. Thanks!
I also added updateShouldNotify: (prev, next) => true,
on the StreamProvider properties but it didn't help one bit.
return Consumer<NotificationProvider>(
builder: (context, provider, child) {
return StreamProvider<ItemsProvider>(
builder: (_) async* {
ItemsProvider _itemsProvider = Provider.of<ItemsProvider>(context);
await _itemsProvider.getItems();
yield _itemsProvider;
},
child: LeContent(),
updateShouldNotify: (prev, next) => true,
);
},
);
I expect the list to update whenever I receive an FCM notification
Upvotes: 0
Views: 1495
Reputation: 341
I solved my own issue by having a StreamBuilder
in a StatefulWidget
.
I have my fetcher as a separate Future<T>
method which will be called on initState
and on didUpdateWidget()
.
Next, in my StatefulWidget
class, I require something that will be used to validate on didUpdateWidget()
's oldWidget.something != widget.something
.
In my case I used the length of the NoticeProvider.notices
which will be incremented every time my FCM configuration triggers it.
in code:
@override
void didUpdateWidget(_Body oldWidget) {
if (oldWidget.alertLength != widget.alertLength) _fetchData();
super.didUpdateWidget(oldWidget);
}
_fetchData, will then call the api, transform the JSON, and add it to the stream
using a StreamController
which, in turn, update the UI.
I hope someone will be helped by this answer in the Future
!
Upvotes: 0
Reputation: 276957
The builder
parameter is called exactly once for the entire life of the StreamProvider
.
The fact that you called Provider.of<ItemsProvider>
doesn't change anything here – the method still won't be called again, even if ItemsProvider
changes.
If you insist in using StreamProvider
, you'll need to somehow transform the Provider.of
into a stream instead.
You can use a StatefulWidget
to do so. Here's an example:
class ProviderToStream<T> extends StatefulWidget {
const ProviderToStream({Key key, this.builder, this.child}) : super(key: key);
final ValueWidgetBuilder<Stream<T>> builder;
final Widget child;
@override
_ProviderToStreamState<T> createState() => _ProviderToStreamState<T>();
}
class _ProviderToStreamState<T> extends State<ProviderToStream> {
final StreamController<T> controller = StreamController<T>();
@override
void dispose() {
controller.close();
super.dispose();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
controller.add(Provider.of<T>(context));
}
@override
Widget build(BuildContext context) {
return widget.builder(context, controller.stream, widget.child);
}
}
You can then do:
ProviderToStream<Foo>(
builder: (_, stream, __) {
return StreamProvider(
builder: (_) async* {
await for (final value in stream) {
// TODO: yield something
}
}
);
}
)
Upvotes: 1