Flutter - StreamBuilder 错误“Bad State:Stream 已经被监听”

时间:2021-02-15 22:47:57

标签: flutter dart socket.io

我在我的 Stateful Widget 中使用了一个切换开关按钮,它设置了一些布尔变量状态是 Builder 是有条件地呈现还是 StreamBuilder

 Expanded(
    child: Padding(
                      padding:
                          const EdgeInsets.fromLTRB(10.0, 32.0, 10.0, 70.0),
                      child: (showPrivate == true && showPublic == false)
                          ? Builder(
                              key: Key("private"),
                              builder: (context) {
                                if (products.length != 0 &&
                                    products.length != null)
                                  return ListView.builder(
                                    scrollDirection: Axis.vertical,
                                    itemCount: products.length,
                                    itemBuilder: (context, i) {
                                      // ListProduct gets product from map
                                      String key = products.keys.elementAt(i);
    
                                      if (products[key].isAmount != "0")
                                        return ListProduct(
                                            products[key], false);
                                      else
                                        return SizedBox();
                                    },
                                  );
                                else
                                  return Center(
                                    child: Text("Empty!"),
                                  );
                              })
                          : (showPrivate == false && showPublic == true)
                              ? Expanded(
                                  child: StreamBuilder(
                                    stream: streamSocket.getResponse,
                                    builder: (context,
                                        AsyncSnapshot<String> snapshot) {
                                      if (snapshot.data != null) {
                                        return Container(
                                          child: Text(snapshot.data),
                                        );
                                      } else {
                                        return ListView.builder(
                                          scrollDirection: Axis.vertical,
                                          itemCount: products.length,
                                          itemBuilder: (context, i) {
                                            // ListProduct gets product from map
                                            String key =
                                                products.keys.elementAt(i);
    
                                            if (products[key].isAmount != "0")
                                              return ListProduct(
                                                  products[key], false);
                                            else
                                              return SizedBox();
                                          },
                                        );
                                      }
                                    },
                                  ),
                                )
                              : Text("")),)

我已经构建了这个自定义流套接字控制器

class StreamSocket {
  var _socketResponse = StreamController<String>();

  void Function(String) get addResponse => _socketResponse.sink.add;
  Stream<String> get getResponse => _socketResponse.stream;

  void connectToWebSocket() async {
    try {
      IO.Socket socket = IO.io(
          "http://localhost:3001/",
          IO.OptionBuilder()
              .setTransports(['websocket'])
              .disableAutoConnect()
              .build());

      socket.connect();

    } catch (err) {
      print("Error: $err");
    }
  }

  void dispose() {
    _socketResponse.close();
  }
}

当我切换 StreamBuilder 超过 2 次并输出此错误时发生错误:

Bad state: Stream has already been listened to.
The relevant error-causing widget was
Expanded

1 个答案:

答案 0 :(得分:0)

您需要在小部件中定义一个流,将其分配给 initState 中的 StreamSocket 流并在 StreamBuilder 中使用它

代码如下:

StreamSocket streamSocket;
Stream<String> stream;

@override
  void initState() {
    streamSocket = StreamSocket();
    stream = streamSocket.getResponse;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
     return  Expanded(
    child: Padding(
                      padding:
                          const EdgeInsets.fromLTRB(10.0, 32.0, 10.0, 70.0),
                      child: (showPrivate == true && showPublic == false)
                          ? Builder(
                              key: Key("private"),
                              builder: (context) {
                                if (products.length != 0 &&
                                    products.length != null)
                                  return ListView.builder(
                                    scrollDirection: Axis.vertical,
                                    itemCount: products.length,
                                    itemBuilder: (context, i) {
                                      // ListProduct gets product from map
                                      String key = products.keys.elementAt(i);
    
                                      if (products[key].isAmount != "0")
                                        return ListProduct(
                                            products[key], false);
                                      else
                                        return SizedBox();
                                    },
                                  );
                                else
                                  return Center(
                                    child: Text("Empty!"),
                                  );
                              })
                          : (showPrivate == false && showPublic == true)
                              ? Expanded(
                                  child: StreamBuilder(
                                    stream: stream,
                                    builder: (context,
                                        AsyncSnapshot<String> snapshot) {
                                      if (snapshot.data != null) {
                                        return Container(
                                          child: Text(snapshot.data),
                                        );
                                      } else {
                                        return ListView.builder(
                                          scrollDirection: Axis.vertical,
                                          itemCount: products.length,
                                          itemBuilder: (context, i) {
                                            // ListProduct gets product from map
                                            String key =
                                                products.keys.elementAt(i);
    
                                            if (products[key].isAmount != "0")
                                              return ListProduct(
                                                  products[key], false);
                                            else
                                              return SizedBox();
                                          },
                                        );
                                      }
                                    },
                                  ),
                                )
                              : Text("")),);
   }