问题
I am trying to use a StreamProvider
(from this awesome package), but I've been struggling to get a particular stream to work.
I create a StreamController
which I use to add data to its Stream
via its Sink
. All of this seems to be working fine. But when using this Stream
with a StreamProvider
, the widget tree does not reflect the changes of the Stream
. It does however work fine using a StreamBuilder
.
The code using a StreamProvider
:
class TestPage extends StatelessWidget {
final Mockup exchange = ExchangeApi.mockup;
@override
Widget build(BuildContext context) {
return StreamProvider<List<Data>>(
builder: (BuildContext context) => Wrapper.mockup.stream,
initialData: null,
catchError: (BuildContext context, e) {
print("Error: $e");
return null;
},
child: TestPageBody(),
);
}
}
class TestPageBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
List<Data> dataList = Provider.of<List<Data>>(context);
return ListView.builder(
itemCount: dataList?.length ?? 0,
itemBuilder: (BuildContext context, int index) {
return Text(dataList[index].name);
},
);
}
}
I have been searching why this does not work, but haven't found an answer yet. But here are some things I did find:
- Using Flutter Desktop Embedding, the UI did reflect changes from the stream when the window got resized (thus forcing to rebuild). The same effect is seen when using hot refresh.
- The stream is constantly adding new data, I tested this by debugging and simply printing out the data
Any help would be greatly appreciated!
回答1:
The default behavior of most providers (excluding ChangeNotifierProvider
) is to assume that the values passed are immutable.
As such, if your stream emits the same value as previously emitted, this won't rebuild dependents.
There are two solutions:
Make the values emitted by your stream immutable, such that performing
previousValue == newValue
works correctly.override
updateShouldNotify
to not filter values if they didn't change.A simple
updateShouldNotify: (_, __) => true
will do.
In the ideal world, prefer immutability.
This can be done by making a copy of your object before sending it to streamController.add(value)
:
List<T> value;
streamController.add(List.from(value));
A second (optional) step is to override updateShouldNotify
(or operator==
on your object) to notify the provider that the value didn't change.
With List
, this can be done using ListEquality
from collection/collection.dart
:
import 'package:provider/provider.dart';
import 'package:collection/collection.dart';
StreamProvider<List<int>>(
builder: (_) => stream,
updateShouldNotify: const ListEquality<int>().equals,
);
来源:https://stackoverflow.com/questions/57365207/streamprovider-not-updating-state