StreamProvider 不更新状态
StreamProvider not updating state
我正在尝试使用 StreamProvider
(来自 this awesome package),但我一直在努力让特定的流工作。
我创建了一个 StreamController
,我用它通过它的 Sink
向它的 Stream
添加数据。所有这一切似乎工作正常。但是当 Stream
与 StreamProvider
一起使用时,小部件树不会反映 Stream
的变化。但是使用 StreamBuilder
确实可以正常工作。
代码使用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);
},
);
}
}
我一直在寻找为什么这不起作用,但还没有找到答案。但这里有一些我确实发现的东西:
- 使用 Flutter Desktop Embedding,当 window 调整大小时(因此强制重建),UI 确实反映了流中的变化。使用热刷新时看到同样的效果。
- 流不断添加新数据,我通过调试和简单打印数据进行了测试
如有任何帮助,我们将不胜感激!
大多数提供程序(不包括 ChangeNotifierProvider
)的默认行为是假定传递的值是不可变的。
因此,如果您的流发出与之前发出的值相同的值,则不会重建依赖项。
有两种解决方法:
使流发出的值不可变,以便执行 previousValue == newValue
正常工作。
覆盖 updateShouldNotify
以在值未更改时不过滤值。
一个简单的updateShouldNotify: (_, __) => true
就可以了。
在理想世界中,更喜欢不变性。
这可以通过在将对象发送到 streamController.add(value)
之前复制对象来完成:
List<T> value;
streamController.add(List.from(value));
第二个(可选)步骤是覆盖 updateShouldNotify
(或您的对象上的 operator==
)以通知提供者该值未更改。
使用 List
,这可以使用 collection/collection.dart
中的 ListEquality
来完成:
import 'package:provider/provider.dart';
import 'package:collection/collection.dart';
StreamProvider<List<int>>(
builder: (_) => stream,
updateShouldNotify: const ListEquality<int>().equals,
);
我正在尝试使用 StreamProvider
(来自 this awesome package),但我一直在努力让特定的流工作。
我创建了一个 StreamController
,我用它通过它的 Sink
向它的 Stream
添加数据。所有这一切似乎工作正常。但是当 Stream
与 StreamProvider
一起使用时,小部件树不会反映 Stream
的变化。但是使用 StreamBuilder
确实可以正常工作。
代码使用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);
},
);
}
}
我一直在寻找为什么这不起作用,但还没有找到答案。但这里有一些我确实发现的东西:
- 使用 Flutter Desktop Embedding,当 window 调整大小时(因此强制重建),UI 确实反映了流中的变化。使用热刷新时看到同样的效果。
- 流不断添加新数据,我通过调试和简单打印数据进行了测试
如有任何帮助,我们将不胜感激!
大多数提供程序(不包括 ChangeNotifierProvider
)的默认行为是假定传递的值是不可变的。
因此,如果您的流发出与之前发出的值相同的值,则不会重建依赖项。
有两种解决方法:
使流发出的值不可变,以便执行
previousValue == newValue
正常工作。覆盖
updateShouldNotify
以在值未更改时不过滤值。一个简单的
updateShouldNotify: (_, __) => true
就可以了。
在理想世界中,更喜欢不变性。
这可以通过在将对象发送到 streamController.add(value)
之前复制对象来完成:
List<T> value;
streamController.add(List.from(value));
第二个(可选)步骤是覆盖 updateShouldNotify
(或您的对象上的 operator==
)以通知提供者该值未更改。
使用 List
,这可以使用 collection/collection.dart
中的 ListEquality
来完成:
import 'package:provider/provider.dart';
import 'package:collection/collection.dart';
StreamProvider<List<int>>(
builder: (_) => stream,
updateShouldNotify: const ListEquality<int>().equals,
);