socket.io-client-dart
socket.io-client-dart copied to clipboard
Double connection?
I created the SocketService class. Inside it there is a method createSocketConnection(), which creates a connection and subscribes to events. The problem is that after Hot Restart the subscription is not closed, if I understand correctly.
My SocketService code:
class SocketService {
late sio.Socket socket;
Map<String, StreamController<String>> messageControllers = {};
Map<String, String> messageTexts = {};
SocketService() {
createSocketConnection();
}
void disconnect() {
socket.disconnect();
}
void createSocketConnection() {
socket = sio.io(
AppConfig.socketUrl,
<String, dynamic>{
'transports': ['websocket'],
'reconnection': true,
'reconnectionAttempts': 5,
'reconnectionDelay': 5000,
'autoConnect': false,
'enableForceNewConnection': false,
},
);
socket.connect();
socket.on('connect', (_) => print('sio: connection success with id ${socket.id}'));
socket.on('connect_error', (data) => print('sio: connection error: $data'));
socket.on('connect_timeout', (data) => print('sio: connection timeout: $data'));
socket.on('reconnect_failed', (_) => print('sio: reconnect failed'));
socket.on('new_token', (data) => _tokenHandler(data));
socket.on('message_end', (data) => _messageEndedHandler(data));
socket.on('shutdown', (_) => socket.disconnect());
}
void sendMessage(String eventType, Map<String, String> data) {
String messageId = data['message_id'] ?? '';
messageControllers[messageId] = StreamController<String>.broadcast();
try {
socket.emit(eventType, data);
} catch (e) {
print(e.toString());
}
}
void receiveMessage(
String messageType,
dynamic Function(dynamic) callback,
) =>
socket.on(messageType, callback);
void _tokenHandler(dynamic data) {
Map<String, dynamic> tokenData = data as Map<String, dynamic>;
String token = tokenData['token'] ?? '';
String messageId = tokenData['message_id'] ?? '';
messageTexts[messageId] = (messageTexts[messageId] ?? '') + token;
messageControllers[messageId]?.add(messageTexts[messageId]!);
}
Stream<String> tokenStream(String messageId) {
return messageControllers[messageId]?.stream ?? const Stream.empty();
}
void _messageEndedHandler(Map<String, dynamic> data) {
String messageId = data['ended_message_id'] ?? '';
print('Message ended: $messageId');
messageControllers[messageId]?.close();
messageControllers.remove(messageId);
messageTexts.remove(messageId);
}
void dispose() {
print('Disposing SocketService');
socket.off('connect');
socket.off('connect_error');
socket.off('connect_timeout');
socket.off('reconnect_failed');
socket.off('new_token');
socket.off('message_end');
for (var controller in messageControllers.values) {
controller.close();
}
messageControllers.clear();
socket.disconnect();
socket.destroy();
}
}
When the application is first started, at the moment when the message_end event is triggered - everything is ok, the _messageEndedHandler method is triggered once. However, after Hot Restart, the method is triggered 2 times. If I do Hot Restart again, the method triggers 3 times.
I am initializing my class as singleton using GetIt:
sl.registerLazySingleton<SocketService>(() => SocketService());
And this how I use it in my app:
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final SocketService _socketService = sl<SocketService>();
@override
void dispose() {
_socketService.dispose();
_client.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
...
);
},
),
);
}
}
Am I doing something wrong?
FYI: not sure whether it's related to this or not - https://github.com/rikulo/socket.io-client-dart#memory-leak-issues-in-ios-when-closing-socket
Please use socket.dispose() instead of socket.close() or socket.disconnect() to solve the memory leak issue on iOS.
@jumperchen None of these solutions work. I already have the autoConnect: false flag set. The dispose() method doesn't work either.
Note: my app works on the web.