在用flutter写IM的时候,当用户很久没有上线过,再次上线的时候,会收到很多离线消息。我是用一个while循环收的,直到收完离线消息,这样可想而知,一点会影响UI的。 消息不多的情况还好,当消息多的时候必然会阻塞UI.
于是这样的任务必须放到子线程去做。而dart中多线程的实现是isolate的方式实现的。在flutter中对Isolate有一定的封装,使用compute, 下面我就用这两种方式各实现一个demo.
- isolate的方式, 通讯是用ReceivePort与SendPort,一个用于发消息,一个用于收消息
import 'dart:async';
import 'dart:isolate';
import 'package:http/http.dart' as http;
main() async {
ReceivePort receivePort = ReceivePort();
await Isolate.spawn(echo, receivePort.sendPort);
// 'echo'发送的第一个message,是它的SendPort
SendPort sendPort = (await receivePort.first) as SendPort;
var msg = await sendReceive(sendPort, "test1");
print('received $msg');
msg = await sendReceive(sendPort, "test2");
print('received $msg');
}
// 新isolate的入口函数, 该函数必须是static或全局函数,该函数不能访问主线程中的变量,只能通过ReceivePort与SendPort将数据传递过去。
echo(SendPort sendPort) async {
// 实例化一个ReceivePort 以接收消息
var port = new ReceivePort();
// 把它的sendPort发送给宿主isolate,以便宿主可以给它发送消息
sendPort.send(port.sendPort);
// 监听消息
await for (var msg in port) {
String data = msg[0] as String;
SendPort replyTo = msg[1] as SendPort;
//在此ioslate中处理,并将结果发给宿主,这里将数据原封不动返回
String result = data ;
replyTo.send(result );
if (data == "test2") port.close();
}
}
/// 对某个port发送消息,并接收结果
Future sendReceive(SendPort port, msg) {
ReceivePort response = new ReceivePort();
//发送消息数据给echo isolate
port.send([msg, response.sendPort]);
//response.first即为从echo isolate接收到的数据
return response.first;
}
上面代码的大意是,开启一个线程,然后主线程发送字符串给子线程,子线程再将字符串原封不懂的发送给主线程。这里主线程每发送一个字符串的时候都需要创建ReceivePort,可以只用一个ReceivePort然后用listen来接收数据
receivePort.listen((value){
});
- compute
function callback( val ) {
...
return res
}
/// `callback` 必须是全局方法或者是类的静态方法
var res = await compute( callback , val );
compute第二个参数就是传递给线程的参数。
需要多线程的朋友,赶快试一试吧。