我正在 Flutter 中实现一个聊天应用程序,其中需要使用单独的隔离来解密消息以防止 UI 阻塞。但是,我遇到了一个问题,即解密的消息没有替换 UI 中的占位符文本。
这是我当前的设置:
initState
中初始化一个解密隔离:void initDecryptionIsolate() async {
decryptionIsolate = await Isolate.spawn(decryptionIsolateEntryPoint, receivePort.sendPort);
receivePort.listen(handleIsolateMessage);
}
isolate
发送解密请求:void sendDecryptionRequest(String messageId, String? encryptedText, String auth) {
if (encryptedText != null && encryptedText.isNotEmpty) {
decryptionIsolate?.controlPort.send({
'messageId': messageId,
'encryptedText': encryptedText,
'auth': auth,
});
}
}
static void decryptionIsolateEntryPoint(SendPort sendPort) {
final ReceivePort receivePort = ReceivePort();
sendPort.send(receivePort.sendPort);
print('Decryption isolate started');
receivePort.listen((message) {
print('Received message in decryption isolate: $message');
if (message is Map<String, dynamic>) {
final auth = message['auth'];
final messageId = message['messageId'];
final encryptedText = message['encryptedText'];
if (messageId != null && encryptedText != null && auth != null) {
try {
final decryptedText =
SecureMessageHandler().decryptMessage(encryptedText, auth);
sendPort.send({
'messageId': messageId,
'decryptedText': decryptedText,
});
} catch (e) {
sendPort.send({
'messageId': messageId,
'decryptedText': 'Error: Failed to decrypt message',
});
}
}
}
});
}
isolate
处理解密消息:void handleIsolateMessage(dynamic message) {
print('Received message in main isolate: $message');
if (message is Map<String, String>) {
final messageId = message['messageId'];
final decryptedText = message['decryptedText'];
if (messageId != null && decryptedText != null) {
setState(() {
decryptedMessageCache[messageId] = decryptedText;
});
appState.updateMessage({
'_id': messageId,
'plain': decryptedText,
'chatroomId': appState.chatroom.value,
});
}
}
}
尽管如此设置,UI 并未使用解密的消息进行更新。占位符文本仍然可见,控制台仅显示:
flutter: Decryption isolate started
flutter: Received message in main isolate: SendPort
在这个实现中我缺少什么来确保解密的消息正确显示在 UI 中?
我的观察是,发送到handleIsolateMessage函数的消息参数的类型为
SendPort
,而不是预期的String Map
。
任何见解或建议将不胜感激!
您不应使用控制端口向您的隔离发送请求。 使用您在步骤 3 中生成的 receivePort :
sendPort.send(receivePort.sendPort);
您正确地将其发送回主隔离区,但您没有在另一侧捕获它(步骤 4):
void handleIsolateMessage(dynamic message) {
print('Received message in main isolate: $message');
// Add this
if (message is SendPort) {
// save reference to the sendPort
// And then use it in your call to "sendDecryptionRequest"
}
else if (message is Map<String, String>) {
final messageId = message['messageId'];
final decryptedText = message['decryptedText'];
if (messageId != null && decryptedText != null) {
setState(() {
decryptedMessageCache[messageId] = decryptedText;
});
appState.updateMessage({
'_id': messageId,
'plain': decryptedText,
'chatroomId': appState.chatroom.value,
});
}
}
}
我强烈建议您仔细阅读 Dart 网站上的这篇精彩文章:Isolates,它详细解释了这一切,并提供了包含错误处理和竞争条件管理的完整代码示例。 另一种方法是使用包WorkerManager,它可能适合您的需求。