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
相关产品推荐
相关产品推荐

