在Android等移动端的开发中,涉及的所有网络操作都不能运行在主线程中。Flutter的网络操作都是通过异步Future进行修饰的,而调用者不需要等待动作返回,也不会造成页面的卡顿。但是,这些异步操作本质上还是Dart语言的并发方案。在Flutter中异步编程与Java不一样,Flutter是单线程运行,也就是说没有多线程的概念,但是Flutter有一个新的概念—隔离,用于实现异步的操作。
隔离是什么?
Flutter的Dart代码是运行在隔离上的,对应的UI主线程在Flutter中称为主隔离(main isolate),我们可以创建一些子隔离用于运行耗时的网络操作,而这些隔离是通过Flutter引擎层的一个线程来控制实现的,而实现隔离的线程又是由Flutter创建和管理的。
隔离的使用
隔离之间的内存是独立的,它们之间进行通信就需要用到Port,一个隔离可以有多个Port,但是Port只有两个类型:ReceivePort和SendPort。其中,ReceivePort是一个接收消息的事件流,SendPort则允许发送消息给ReceivePort。SendPort可以由ReceivePort生成,它将所有的消息发送给对应的ReceivePort。
_main() async {
final receivePort = ReceivePort();
//创建隔离
await Isolate.spawn(_isolate2, receivePort.sendPort);
//发送消息
var sendPort = await receivePort.first;
var message = await sendMessage(sendPort, "哈喽");
print('Main_Isolate:$message');
}
void _isolate2(SendPort message) async {
//创建一个ReceivePort
var port = ReceivePort();
//把它发送给主隔离
message.send(port.sendPort);
port.listen((message) {
SendPort send = message[0] as SendPort;
String str = message[1] as String;
print('Isolate2:$str');
send.send("message");
port.close();
});
}
Future sendMessage(sendPort, String message) async {
ReceivePort receivePort = ReceivePort();
sendPort.send([receivePort.sendPort, message]);
return receivePort.first;
}
在一个隔离中创建另一个隔离被称为spawning。除了spawn()方法生成隔离外,还可以用spawnUri()方法,它是基于给定库的URI来生成一个隔离。
隔离的简单使用
上面隔离的使用比较复杂,对于一些只有一次返回的异步请求,使用上面的方式显然不那么划算了。这时候可以使用Flutter提供的compute()函数,它只有两个参数,第一个参数是需要执行耗时任务的名称,第二个参数是前面方法需要传递的参数。此外,compute()函数中运行的方法必须是顶级方法或者是static方法,并且compute()函数只能传递一个参数,返回值也只有一个。
Future<bool> isPrime(int value) {
return compute(_calculate, value);
}
bool _calculate(int value) {
if (value == 1) {
return false;
}
for (int i = 2; i < value; ++i) {
if (value % i == 0) {
return false;
}
}
return true;
}
总结
对于一些需要多次返回的场景,比如我们socket长链接与后台通信,这时候如果使用compute函数就不能满足需求了,所以对于这类场景只能使用isolate来实现。