You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter异步函数返回Widget报错:期望Widget类型却得到_Future类型

错误修复:Expected a value of type 'Widget', but got one of type '_Future'

问题根源

CreateServer()是异步函数,调用后返回的是Future<ChatAsServer>类型,而Flutter的Widget树只能接受Widget类型节点,直接将Future当作Widget使用就会触发类型不匹配错误。同时原CreateServer()存在逻辑缺陷:await for循环中第一次收到请求就返回,导致服务器仅处理一个连接就停止,不符合WebSocket服务器的持续运行需求。

修复步骤

1. 重构服务器初始化逻辑

将服务器启动与连接监听分离,让服务器持续运行,同时用状态管理保存连接列表:

import 'dart:io';
import 'package:web_socket_channel/io.dart';

HttpServer? _server;
final List<IOWebSocketChannel> _activeChannels = [];

// 启动WebSocket服务器的异步方法
Future<void> startServer() async {
  _server = await HttpServer.bind(InternetAddress.anyIPv4, 4747);
  print('服务器已启动,监听端口4747');
  
  await for (HttpRequest request in _server!) {
    final webSocket = await WebSocketTransformer.upgrade(request);
    final channel = IOWebSocketChannel(webSocket);
    _activeChannels.add(channel);
    
    // 监听消息与连接断开事件
    channel.stream.listen(
      (message) {
        // 可选:广播消息给所有其他连接
        for (var c in _activeChannels) {
          if (c != channel) c.sink.add(message);
        }
      },
      onDone: () => _activeChannels.remove(channel),
    );
  }
}

2. 使用FutureBuilder处理异步UI渲染

在需要展示ChatAsServer的位置,用FutureBuilder包裹,处理服务器启动的异步过程:

// 在父页面的build方法中
@override
Widget build(BuildContext context) {
  return FutureBuilder(
    future: startServer(),
    builder: (context, snapshot) {
      switch (snapshot.connectionState) {
        case ConnectionState.waiting:
          return const Center(child: CircularProgressIndicator());
        case ConnectionState.done:
          // 服务器启动完成,等待客户端连接
          return _activeChannels.isNotEmpty
              ? ChatAsServer(channel: _activeChannels.first)
              : const Center(child: Text('等待客户端连接...'));
        default:
          return const Center(child: Text('服务器启动异常'));
      }
    },
  );
}

3. 修正ChatAsServer的状态管理问题

将TextEditingController的初始化移到initState中,避免每次重建Widget都创建新实例:

class _ChatAsServerState extends State<ChatAsServer> {
  late IOWebSocketChannel channel;
  late TextEditingController _smsController;
  final List<Widget> _messages = [];

  @override
  void initState() {
    super.initState();
    channel = widget.channel;
    _smsController = TextEditingController();
    
    // 监听WebSocket消息,更新本地消息列表
    channel.stream.listen((message) {
      setState(() {
        _messages.add(mess(message, MediaQuery.of(context).size.width, false));
      });
    });
  }

  @override
  void dispose() {
    _smsController.dispose();
    channel.sink.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final double width = MediaQuery.of(context).size.width;
    // ... 保留原Scaffold结构,修改消息列表部分为:
    Expanded(
      child: ListView.builder(
        itemCount: _messages.length,
        itemBuilder: (context, index) => _messages[index],
      ),
    );
    // ... 其余代码不变
  }
}

4. 修正消息发送逻辑

原代码仅添加消息到本地列表,需补充发送到WebSocket的逻辑:

IconButton(
  onPressed: () {
    if (_smsController.text.isNotEmpty) {
      setState(() {
        _messages.add(mess(_smsController.text, width, true));
      });
      channel.sink.add(_smsController.text);
      _smsController.clear();
    }
  },
  // ... 其余属性不变
)

总结

  • 异步函数返回的Future不能直接作为Widget使用,必须通过FutureBuilder或状态管理处理异步结果
  • WebSocket服务器需持续运行,不能处理单个连接后就终止
  • Widget的控制器和状态应在initState中初始化,避免重复创建导致的性能问题

内容的提问来源于stack exchange,提问作者Dev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 18:33:31