Flutter socket_io_client登录/登出后无法重新加入房间问题
Flutter Socket.IO 重登后无法加入房间的问题修复
核心问题分析
你的代码存在以下几个关键问题导致重登失败:
- 未等待Socket连接建立就发送事件:
_initializeSocket里直接调用socket.emit,但此时Socket可能还处于连接握手阶段,事件会发送失败 - 旧Socket实例未彻底清理:登出时仅调用
disconnect,但旧的Socket对象仍然存在,重登创建新实例时可能出现状态冲突 - Socket实例重置不彻底:重登时直接覆盖
socket变量,没有确保旧实例完全销毁
修复后的完整代码
class AppBloc extends Bloc<AppEvent, AppState> with ChangeNotifier { AppBloc({required AuthService authenticationRepository, bool authenticated = false}) : _authenticationRepository = authenticationRepository, super( authenticated ? AppState.authenticated(authenticationRepository.currentUser) : const AppState.unauthenticated(), ) { on<AppUserChanged>(_onUserChanged); on<AppLogoutRequested>(_onLogoutRequested); _userSubscription = _authenticationRepository.user.listen( (user) { add(AppUserChanged(user)); notifyListeners(); }, ); if (authenticated && _authenticationRepository.currentUser.isNotEmpty) { _initializeSocket(authenticationRepository.currentUser); } } void _initializeSocket(User currentUser) { // 初始化前先清理可能存在的旧socket _cleanupSocket(); socket = IO.io('http://localhost:3000', <String, dynamic>{ 'transports': ['websocket'], }); // 等待连接成功后再发送加入房间事件 socket.onConnect((_) { socket.emit('joinUserRoom', currentUser.id); print('Socket连接成功,已加入用户房间:${currentUser.id}'); }); // 监听连接错误,便于调试 socket.onConnectError((error) { print('Socket连接错误:$error'); }); } IO.Socket? socket; // 改为可空类型,便于置空清理 final AuthService _authenticationRepository; late StreamSubscription<User> _userSubscription; void _onUserChanged(AppUserChanged event, Emitter<AppState> emit) { if (event.user.isNotEmpty) { _initializeSocket(event.user); } else { _cleanupSocket(); } emit( event.user.isNotEmpty ? AppState.authenticated(event.user) : const AppState.unauthenticated(), ); notifyListeners(); } // 彻底清理socket:断开连接、销毁实例、置空变量 void _cleanupSocket() { if (socket != null) { if (socket!.connected) { socket!.disconnect(); } socket!.dispose(); socket = null; } } void _onLogoutRequested(AppLogoutRequested event, Emitter<AppState> emit) { _cleanupSocket(); _authenticationRepository.logOut(); emit(const AppState.unauthenticated()); notifyListeners(); } @override Future<void> close() { _cleanupSocket(); _userSubscription.cancel(); return super.close(); } }
关键修改说明
- 等待连接成功再发送事件:通过
socket.onConnect回调确保Socket连接完成后再发送joinUserRoom,避免事件丢失 - 彻底清理Socket实例:新增
_cleanupSocket方法,负责断开连接、调用dispose销毁实例,并将socket变量置空,彻底清除旧实例的影响 - Socket变量改为可空类型:将
late IO.Socket socket改为IO.Socket? socket,便于在清理时置空,避免未初始化的问题 - 添加错误监听:增加
onConnectError回调,便于调试连接过程中出现的问题 - 初始化前先清理:在
_initializeSocket开头先调用_cleanupSocket,确保创建新Socket前没有残留的旧实例
内容的提问来源于stack exchange,提问作者Giga Ananidze
相关产品推荐
相关产品推荐

