如何套接 asBroadcastStream 以便它可以在流生成器中使用?

How to socket a asBroadcastStream so that it can be used in a stream builder?

你好我 运行 遇到一个关于 Streams 的问题,特别是关于如何使用广播流进行套接字编程。这是代码:

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'dart:io';
import 'dart:typed_data';
import 'package:tcp/othermessage.dart';
import 'package:tcp/ownmessage.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:google_fonts/google_fonts.dart';

void main() async {
  final socket =
      await Socket.connect('0.0.0.0', 3389); //This ip wouldn't work but I change it for safety reasons
  print('Connected to: ${socket.remoteAddress.address}:${socket.remotePort}');
  runApp(MyApp(socket: socket));
  socket.write("h");
}

class MyApp extends StatelessWidget {
  final Socket socket;

  const MyApp({required this.socket, Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page', socket: socket),
    );
  }
}

class MyHomePage extends StatefulWidget {
  final Socket socket;

  MyHomePage({Key? key, required this.title, required this.socket})
      : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final inputController = TextEditingController();

  ScrollController scrollcontrol = ScrollController();

  List<String> messageList = [];

  @override
  void dispose() {
    inputController.dispose();
    widget.socket.destroy();
    widget.socket.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: const Color.fromRGBO(236, 236, 236, 1),
        body: SafeArea(
          child: Column(
            children: <Widget>[
              StreamBuilder(
                  stream: widget.socket,
                  builder: (context, snapshot) {
                    if (snapshot.hasData == false ||
                        String.fromCharCodes(snapshot.data as Uint8List)
                                .contains("joined Connected to the server!") ==
                            true) {
                      return Container(
                          height: MediaQuery.of(context).size.height - 300);
                    }
                    String sent =
                        String.fromCharCodes(snapshot.data as Uint8List);
                    messageList.add(sent);
                    return Container(
                        color: const Color.fromRGBO(236, 235, 236, 100),
                        height: MediaQuery.of(context).size.height - 300,
                        child: ListView.builder(
                            controller: scrollcontrol,
                            shrinkWrap: true,
                            itemCount: messageList.length,
                            itemBuilder: (BuildContext context, int index) {
                              String messagerecieved = messageList[index];
                              List<String> messagedisected =
                                  messagerecieved.split(" ");
                              if (messagedisected[0] != "h:" &&
                                  messagerecieved.contains(
                                          "joined Connected to the server!") ==
                                      false) {
                                return OtherMessage(
                                    message: messageList[index]);
                              } else {
                                return OwnMessage(message: messageList[index]);
                              }
                            }));
                  }),
              Row(
                children: [
                  Container(
                    margin: EdgeInsets.only(left: 12),
                    width: 330,
                    decoration: BoxDecoration(
                        color: Color.fromRGBO(214, 214, 214, 100),
                        borderRadius: BorderRadius.circular(14.65)),
                    child: TextFormField(
                      keyboardType: TextInputType.multiline,
                      minLines: 1,
                      maxLines: 5,
                      decoration: const InputDecoration(
                          hintText: 'Enter your message',
                          border: InputBorder.none,
                          focusedBorder: InputBorder.none,
                          enabledBorder: InputBorder.none,
                          errorBorder: InputBorder.none,
                          disabledBorder: InputBorder.none,
                          contentPadding: EdgeInsets.only(
                              left: 15, bottom: 11, top: 11, right: 15)),
                      controller: inputController,
                    ),
                  ),
                  IconButton(
                      padding:
                          const EdgeInsets.only(left: 10, right: 12, top: 10),
                      iconSize: 50,
                      onPressed: () {
                        if (messageList.isNotEmpty) {
                          scrollcontrol.animateTo(
                              scrollcontrol.position.maxScrollExtent,
                              duration: const Duration(milliseconds: 100),
                              curve: Curves.easeOut);
                        }
                        String message = inputController.text;
                        widget.socket.write("h: " + message);
                        inputController.clear();
                      },
                      icon: SvgPicture.asset('assets/images/SendButton.svg'))
                ],
              ),
            ],
          ),
        ));
  }
}

我希望能够将套接字公开为广播流,我已经尝试使用 asBroadcastStream 函数,但我不知道如何将它传递给另一个 StreamBuilder。我的计划是能够读取 tcp 服务器发送的状态并使用 StreamBuilder 更新我的 AppBar 标题

AppBar(title: StreamBuilder<Object>(
    stream: widget.socket,
    builder: (context, snapshot) {
      return mycustomwidget();
    }
  )

我们知道这样做是不可能的,因为流不是广播流并且已经被另一个流生成器收听,我尝试像这样使用 asBroadCastStream

class _MyHomePageState extends State<MyHomePage> {
  final inputController = TextEditingController();

  ScrollController scrollcontrol = ScrollController();

  List<String> messageList = [];

   Stream mystream=widget.socket.asBroadcastStream();
 
  @override
  void dispose() {
    inputController.dispose();
    widget.socket.destroy();
    widget.socket.close();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    mystream.listen((value)=>print(value));

    return Scaffold(//...continuation

但显然它又返回了一个 badState。我在处理这样的流方面仍然很陌生,我希望有人能澄清并解决我的问题。谢谢!

你好,把我的脑袋扯下来后,原来你可以用 asBroadcastStream 函数来做,这个函数之前会产生错误,因为我一直在 onDestroy 和另一个 streambuilder 中使用 widget.socket将其传递给新流,然后将其用于其他流构建器。

class _MyHomePageState extends State<MyHomePage> {
  final inputController = TextEditingController();

  ScrollController scrollcontrol = ScrollController();

  List<String> messageList = [];

  late Stream broadcaststream;

  @override
  void initState() {
    // TODO: implement initState
    broadcaststream = widget.socket.asBroadcastStream();
    super.initState();
  }

  @override
  void dispose() {
    inputController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
            title: StreamBuilder(
                stream: broadcaststream,
                builder: (context, snapshot) {
                  if (snapshot.hasData == false) {
                    return (Text("Connecting"));
                  }
                  return (Text(
                      String.fromCharCodes(snapshot.data as Uint8List)));
                })),
        backgroundColor: Colors.white,
        body: SafeArea(
          child: SingleChildScrollView(
            reverse: true,
            child: Column(
              children: <Widget>[
                StreamBuilder(
                    stream: broadcaststream,
                    builder: (context, snapshot) {
                      if (snapshot.hasData == false ||
                          String.fromCharCodes(snapshot.data as Uint8List)
                                  .contains("Connected to the server!") ==
                              true) {
                        return Container(
                            height: MediaQuery.of(context).size.height - 300);
                      }
                      String sent =
                          String.fromCharCodes(snapshot.data as Uint8List);
                      messageList.add(sent);
                      return Container(
                          color: const Color.fromRGBO(236, 235, 236, 100),
                          height: MediaQuery.of(context).size.height - 300,
                          child: ListView.builder(
                              controller: scrollcontrol,
                              shrinkWrap: true,
                              itemCount: messageList.length,
                              itemBuilder: (BuildContext context, int index) {
                                String messagerecieved = messageList[index];
                                List<String> messagedisected =
                                    messagerecieved.split(" ");
                                if (messagedisected[0] != "${widget.title}:" &&
                                    messagerecieved.contains(
                                            "Connected to the server") ==
                                        false) {
                                  print(messagedisected[0]);
                                  return OtherMessage(
                                      message: messageList[index]);
                                } else {
                                  return OwnMessage(
                                      message: messageList[index]);
                                }
                              }));
                    }),
                Row(
                  children: [
                    Container(
                      margin: EdgeInsets.only(left: 12),
                      width: 330,
                      decoration: BoxDecoration(
                          color: Color.fromRGBO(214, 214, 214, 100),
                          borderRadius: BorderRadius.circular(14.65)),
                      child: TextFormField(
                        keyboardType: TextInputType.multiline,
                        minLines: 1,
                        maxLines: 5,
                        decoration: const InputDecoration(
                            hintText: 'Enter your message',
                            border: InputBorder.none,
                            focusedBorder: InputBorder.none,
                            enabledBorder: InputBorder.none,
                            errorBorder: InputBorder.none,
                            disabledBorder: InputBorder.none,
                            contentPadding: EdgeInsets.only(
                                left: 15, bottom: 11, top: 11, right: 15)),
                        controller: inputController,
                      ),
                    ),
                    IconButton(
                        padding:
                            const EdgeInsets.only(left: 10, right: 12, top: 10),
                        iconSize: 50,
                        onPressed: () {
                          if (messageList.isNotEmpty) {
                            scrollcontrol.animateTo(
                                scrollcontrol.position.maxScrollExtent,
                                duration: const Duration(milliseconds: 100),
                                curve: Curves.easeOut);
                          }
                          String message = inputController.text;
                          widget.socket.write("${widget.title}: " + message);
                          inputController.clear();
                        },
                        icon: SvgPicture.asset('assets/images/SendButton.svg'))
                  ],
                ),
              ],
            ),
          ),
        ));
  }
}``