Flutter 如果StreamBuilder中的流返回null,我必须做什么?

Flutter 如果StreamBuilder中的流返回null,我必须做什么?,flutter,dart,Flutter,Dart,我正在尝试将websocket与此软件包一起使用,一切正常,直到我意识到如果通道第一次无法与服务器连接,则流将为null,我得到以下错误: 对null调用了getter“stream” 我将频道设置为一个单例类,这样我就可以在我的应用程序中的任何地方调用close或add: class WebSocket { static IOWebSocketChannel channel; static init() async { try { String macAddress

我正在尝试将websocket与此软件包一起使用,一切正常,直到我意识到如果通道第一次无法与服务器连接,则流将为null,我得到以下错误:

对null调用了getter“stream”

我将频道设置为一个单例类,这样我就可以在我的应用程序中的任何地方调用close或add:

class WebSocket {
  static IOWebSocketChannel channel;
  static init() async {
    try {
      String macAddress = await getMacAddress();
      channel = IOWebSocketChannel.connect("ws://172.16.0.39:8001/ws/fsmart-door/$macAddress");
    } catch (e) {
      debugPrint(e.toString());
    }
  }
}
我在main中调用Websocket.init(),这样通道就可以进行流传输了,但是如果IOWebSocketChannel.connect无法连接,应用程序也会被卡住

这是我的StreamBuilder:

StreamBuilder(
  stream:  WebSocket.channel.stream,
  builder: (context, snapshot) {
    if (snapshot.hasData) {

    }
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 24.0),
      child: Text(snapshot.hasData ? '${snapshot.data}' : ''),
    );
 },

问题是当连接失败时,
channel
null
,因此您不能执行
channel.stream
,而
StreamBuilder
不能有
流。因此,您可以采取的一种方法是在
WebSocket
中有一个
Stream
来处理重试操作,当
频道
就绪时,将来自
channel.Stream
的数据传递到
WebSocket

这就是
WebSocket

class WebSocket {
  static WebSocket _instance;
  final _streamController = StreamController.broadcast();
  IOWebSocketChannel channel;

  static WebSocket get instance {
    if (_instance == null) {
      _instance = WebSocket();
    }
    return _instance;
  }

  Stream get channelStream => _streamController.stream;

  Future init(int retries) async {
    if (channel == null) {
      await _tryToConnect(retries);
      if (channel != null) {
        _streamController.sink.add(null);
        channel.stream.listen((value) {
          _streamController.sink.add(value);
        });
      } else {
        _streamController.sink.addError("Could not connect");
      }
    }
  }

  Future _tryToConnect(int retries) async {
    if (channel == null) {
      try {
        String macAddress = await getMacAddress();
        // This is to throw exception if it can't connect (https://github.com/dart-lang/web_socket_channel/issues/38#issuecomment-450383558)
        final socket = await WebSocket.connect(
                "ws://172.16.0.39:8001/ws/fsmart-door/$macAddress")
            .timeout(_webSocketConnectionTimeout);
        channel = IOWebSocketChannel(socket);
      } catch (e) {
        debugPrint(e.toString());
      }
      if (channel == null && retries > 0) {
        _streamController.sink.addError("Retries left: ${retries - 1}");
        await _tryToConnect(retries - 1);
      }
    }
  }

  void close() => _streamController.close();
}
@override
void initState() {
  super.initState();
  WebSocket.instance.init(5);
}

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: StreamBuilder(
        stream: WebSocket.instance.channelStream,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return Text('Data: ${snapshot.data}');
          } else if (snapshot.hasError) {
            return Text('Error: ${snapshot.error}');
          }
          return Text('Loading...');
        },
      ),
    ),
  );
}
这将是
StreamBuilder

StreamBuilder(
  stream: WebSocket.instance.channelStream,
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      return Text('Data: ${snapshot.data}');
    } else if (snapshot.hasError) {
      return Text('Error: ${snapshot.error}');
    }
    return Text('Loading...');
  },
)

如果要对此解决方案进行快速测试,请更换
try
catch
中的两行,以便:

await Future.delayed(Duration(seconds: 3));
if (retries == 2) channel = IOWebSocketChannel();
使用此
IOWebSocketChannel

class IOWebSocketChannel {
  var _streamController = StreamController<String>.broadcast();

  IOWebSocketChannel() {
    init();
  }

  Stream get stream => _streamController.stream;

  Future init() async {
    await Future.delayed(Duration(seconds: 3));
    _streamController.sink.add("1");
    await Future.delayed(Duration(seconds: 3));
    _streamController.sink.add("2");
  }

  void close() => _streamController.close();
}

如果频道无法连接,您想做什么?只是显示错误,尝试自动重新连接或添加按钮尝试重新连接?我想自动重新连接我已尝试为通道检查null,但问题是IOWebSocketChannel。connect()仍然返回IOWebSocketChannel,即使它无法连接,因此我无法检查它以调用重新连接通道。但是,您的工具很棒。我已经解决了我的问题,虽然它有点不灵活。感谢您的帮助。我正在检查WebSocket的通道变量是否为null,而不是connect()返回的通道。我假设如果它不能连接,它会抛出一个异常,这样通道就不会被分配。即使它没有抛出异常,您也可以检查通道==null | |!channel.isConnected()或任何您必须知道它是否已连接的方法在tryToConnect中,通道是从connect分配的,因此它无法调用重新连接,因为它不能为null,它也不会引发异常,我已经尝试过了。对不起,我不能接受你的道歉,请投票给伟大的工具。谢谢你没问题,我只是想知道这是怎么回事。如果connect返回一个对象但未连接,您如何知道该对象未连接?