dart语言默认是单线程的,这就导致了如果在处理一个耗时比较长事务的话,很有可能会造成UI渲染的阻塞。举例子:我在页面创建一个动画,然后执行一个计算的函数,而这个计算的函数耗时比较长,这个时候你就可以看到,动画在UI上会被卡住,直到计算函数执行完毕动画恢复正常。
import 'dart:isolate';
import 'package:flutter/material.dart';
class IsolateTest extends StatefulWidget {
const IsolateTest({Key? key}) : super(key: key);
@override
State createState() => _IsolateTestState();
}
class _IsolateTestState extends State {
int _count = 0;
//耗时工作,计算偶数个数
static int calculateEvenCount(int num) {
int count = 0;
while (num > 0) {
if (num % 2 == 0) {
count++;
}
num--;
}
return count;
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 100,
height: 100,
child: CircularProgressIndicator(),
),
Text(_count.toString()),
TextButton(
onPressed: () {
//触发耗时操作
_count = calculateEvenCount(1000000000);
setState(() {});
},
child: Text('开始耗时工作[在主线程]'),
)
],
),
);
}
}
在dart 2.15以前,isolate是一个独立的包,在pub可以下载。在dart2.15后它已经集成在了sdk里面,不需要在单独下载包了。它是dart官方针对多线程给出的解决方案。它可以不占用主线程的情况下,另开线程去执行相应事务。但是这个isolate每个会消耗2m的内存资源,需要按实际场景具体谨慎使用。一下是对比效果代码。
首先我们创建一个线程管理
import 'dart:isolate';
class ThreadManagement {
//entryPoint 必须是静态方法
static Future runTask(void Function(SendPort message) entryPoint, Function(T value) callback, {Object? parameter}) async {
final response = ReceivePort();
Isolate d = await Isolate.spawn(entryPoint, response.sendPort);
// 调用sendReceive自定义方法
if (parameter != null) {
SendPort sendPort = await response.first;
ReceivePort receivePort = ReceivePort();
sendPort.send([parameter, receivePort.sendPort]);
receivePort.listen((value) {
receivePort.close();
d.kill();
callback(value);
});
} else {
response.listen((value) {
response.close();
d.kill();
callback(value);
});
}
}
}
页面调用
import 'dart:isolate';
import 'package:flutter/material.dart';
class IsolateTest extends StatefulWidget {
const IsolateTest({Key? key}) : super(key: key);
@override
State createState() => _IsolateTestState();
}
class _IsolateTestState extends State {
int _count = 0;
//耗时工作,计算偶数个数
static int calculateEvenCount(int num) {
int count = 0;
while (num > 0) {
if (num % 2 == 0) {
count++;
}
num--;
}
return count;
}
//模拟Future耗时
void doMockTimeConsume() async {
// 调用无参数的任务
ThreadManagement.runTask(getParamsTask, (value) {
_count = value;
if (mounted) {
setState(() {});
}
}, parameter: 1000000000);
}
// 需要参数的任务
static getParamsTask(SendPort port) async {
ReceivePort receivePort = ReceivePort();
port.send(receivePort.sendPort);
// 监听外界调用
await for (var msg in receivePort) {
int n = msg[0];
SendPort callbackPort = msg[1];
receivePort.close();
int res = calculateEvenCount(n);
callbackPort.send(res);
}
}
// // 无参数的任务,例子
// static void getNoParamTask(SendPort port) async {
// var c = await Future.delayed(Duration(seconds: 1), () {
// return "banner data";
// });
// port.send(c);
// }
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 100,
height: 100,
child: CircularProgressIndicator(),
),
Text(_count.toString()),
TextButton(
onPressed: () {
//触发耗时操作
doMockTimeConsume();
},
child: Text('开始耗时工作[另开线程]'),
),
TextButton(
onPressed: () {
//触发耗时操作
_count = calculateEvenCount(1000000000);
setState(() {});
},
child: Text('开始耗时工作[在主线程]'),
)
],
),
);
}
}