7

我正在尝试使用一个StreamProvider(来自这个很棒的包),但我一直在努力让一个特定的流工作。

我创建了一个用于通过其向其StreamController添加数据的. 所有这些似乎都运行良好。但是当它与 a 一起使用时,小部件树不会反映. 但是,使用. StreamSinkStreamStreamProviderStreamStreamBuilder

使用的代码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,当窗口调整大小(从而强制重建)时,UI 确实反映了流中的变化。使用热刷新时可以看到相同的效果。
  • 流不断添加新数据,我通过调试测试了这一点,并简单地打印出数据

任何帮助将不胜感激!

4

1 回答 1

18

大多数提供者(不包括ChangeNotifierProvider)的默认行为是假设传递的值是不可变的。

因此,如果您的流发出与之前发出的相同的值,则不会重建依赖项。

有两种解决方案:

  • 使您的流发出的值不可变,以便执行previousValue == newValue正常工作。

  • updateShouldNotify如果值没有更改,则覆盖以不过滤值。

    一个简单的updateShouldNotify: (_, __) => true就可以了。


在理想世界中,更喜欢不变性。

这可以通过在将对象发送到之前复制对象来完成streamController.add(value)

List<T> value;
streamController.add(List.from(value));

第二个(可选)步骤是覆盖updateShouldNotify(或operator== 在您的对象上)以通知提供者该值没有更改。

使用List,这可以使用ListEqualityfrom来完成collection/collection.dart

import 'package:provider/provider.dart';
import 'package:collection/collection.dart';

StreamProvider<List<int>>(
  builder: (_) => stream,
  updateShouldNotify: const ListEquality<int>().equals,
);
于 2019-08-05T20:06:36.077 回答