调用 StreamController.sink.add 时 StreamBuilder 没有反应

Posted

技术标签:

【中文标题】调用 StreamController.sink.add 时 StreamBuilder 没有反应【英文标题】:StreamBuilder is not reacting when calling StreamController.sink.add 【发布时间】:2019-08-18 00:31:31 【问题描述】:

我的 Flutter 应用中有一个专门用于编辑对象列表的屏幕。当您按下编辑按钮时,会弹出一个模式,允许您编辑对象值。当您关闭模型时,列表会通过 BLoC 刷新。但是,当调用刷新列表的方法时,什么也没有发生。

bloc.dart
class Bloc 

  final _provider = ModelProvider();
  final _controller = StreamController<List<Model>>();

  Stream<List<Model>> get models => _controller.stream;

  void getModels() async 
    final List<Model> models = await _provider.readAll();
    _controller.sink.add(models);
  

  Future<int> saveModel(Model model) async 
    final int id = await _provider.write(model);
    return id;
  


list_screen.dart
class ListScreen extends StatelessWidget 

  final bloc = Bloc();

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          // SliverAppBar ...
          StreamBuilder<List<Model>>(
            stream: bloc.models,
            builder: (context, snapshot) 
              if (snapshot.hasData) 
                return ListView.builder(
                  itemCount: snapshot.data.length,
                  itemBuilder: (context, index) =>
                      ListTile(
                        title: Text(snapshot.data[index].name),
                        onPressed: () => _editModel(context),
                      ),
                ),
               else 
                bloc.getModels();
                return Container();
              
                      
          ),
        ],
      ),
    );
  

  void _editModel(BuildContext context) async 
    final Model edited = await showDialog(
      context: context,
      builder: (context) => EditModal(),
    );
    if (edited != null) 
      await bloc.saveModel(edited);
      bloc.getModels();
    
  


我知道数据已正确存储在数据库中,因为如果我转到上一个屏幕然后返回到编辑屏幕,数据就会更新。谁能帮我弄清楚为什么StreamBuilder 没有重建?

【问题讨论】:

您解决了吗?我刚刚进入 Flutter 开发并遇到了这个确切的问题。 我从未解决过这个问题。我切换到 Provider 进行状态管理,但这对我来说很容易,因为我处于开发的早期阶段。 【参考方案1】:

也许问题是你在保存后调用 bloc.getModels 时没有放置等待,或者保存方法给出错误并破坏不运行 getModels 的方法

【讨论】:

awaitBloc.getModels 一起使用将不起作用,因为它不会返回Future,而且我知道数据存储正确,因为我可以在@987654325 中打印models @ 并看到它获取更新的数据。【参考方案2】:

希望这会对某人有所帮助:对我来说,问题在于,当我更新列表时,它实际上是存储在字段中的相同引用。每次创建一个新列表并且不将列表存储在同一字段中解决了它。我们无法从问题中看到您的 ModelProvider 内部,但看起来可能是同一个问题。

第一次之后没有更新:

class MiniaturePaintsBloc implements Bloc 

  List<MiniaturePaint> _miniaturePaints;

  final _controller = StreamController<List<MiniaturePaint>>.broadcast();

  Stream<List<MiniaturePaint>> get miniaturePaintsStream => _controller.stream;

  void fetchMiniaturePaints() async 
    QuerySnapshot querySnapshot =
        await Firestore.instance.collection("MiniaturePaints").getDocuments(source: Source.serverAndCache);
    _miniaturePaints = querySnapshot.documents.map((doc) => _docToMiniaturePaint(doc)).toList();
    _controller.sink.add(_miniaturePaints);
  

  //rest of BloC code here

通过删除该字段,它现在会更新 StreamBuilder:

class MiniaturePaintsBloc implements Bloc 

  final _controller = StreamController<List<MiniaturePaint>>.broadcast();

  Stream<List<MiniaturePaint>> get miniaturePaintsStream => _controller.stream;

  void fetchMiniaturePaints() async 
    QuerySnapshot querySnapshot =
        await Firestore.instance.collection("MiniaturePaints").getDocuments(source: Source.serverAndCache);
    List<MiniaturePaint> miniaturePaints = querySnapshot.documents.map((doc) => _docToMiniaturePaint(doc)).toList();
    _controller.sink.add(miniaturePaints);
  

  //rest of BLoC code here

【讨论】:

这在技术上是完全一样的。没有什么区别。您正在将 _miniaturePaints 列表更改为两个代码 sn-ps 中的不同列表。一个是字段这一事实没有任何区别,因为它是我们想要的数据,而不是它是字段还是变量。

以上是关于调用 StreamController.sink.add 时 StreamBuilder 没有反应的主要内容,如果未能解决你的问题,请参考以下文章

系统调用与函数调用

java三种调用方式(同步调用/回调/异步调用)

LINUX系统调用

引用调用 vs 复制调用调用

RPC 调用和 HTTP 调用的区别

js方法调用