Flutter隔离执行插件use_isolate的使用
Flutter隔离执行插件use_isolate的使用
integral_isolates
的强大功能被巧妙地封装在了一个 flutter_hooks
的钩子中。
使用方法
使用隔离(isolate)在钩子中从未如此简单。通过使用 useIsolate()
,你可以获得一个类似于 compute
的计算函数,但它的生命周期更长。你无需关心生命周期管理,因为钩子会为你处理。
示例代码:
class TestingIsolateHook extends HookWidget {
const TestingIsolateHook({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
final isolate = useIsolate(); // 获取一个隔离实例
final number = useState(1); // 定义一个状态变量
return TextButton(
onPressed: () async {
final isPrime = await isolate.compute(_isPrime, number.value); // 在隔离中执行计算
print('${number.value} 是素数吗? ${isPrime}');
number.value += 1; // 更新状态变量
},
child: Text(
'检查 ${number.value} 是否为素数',
),
);
}
static bool _isPrime(int value) {
if (value == 1) {
return false;
}
for (int i = 2; i < value; ++i) {
if (value % i == 0) {
return false;
}
}
return true;
}
}
说明:
useIsolate()
返回一个隔离实例。useState()
定义一个可变的状态变量。isolate.compute()
在隔离中执行计算。number.value += 1
更新状态变量。
回压策略
该钩子支持回压策略(backpressure strategies)。只需将策略作为参数传递即可:
final isolate = useIsolate(backpressureStrategy: DiscardNewBackPressureStrategy());
尾调隔离(Tailored Stateful Isolate)
你可能知道,你可以用 integral_isolates
创建尾调隔离。现在,使用 use_isolate
也可以实现这一点。
创建一个接收 double
类型输入并返回 int
类型结果的尾调隔离,可以这样使用:
final isolate = useTailoredIsolate<double, int>();
突破性变更
use_isolate
v0.3.0:现在返回整个隔离实例,需要显式调用isolate.compute(...)
而不是isolate(...)
. 这是为了支持isolate.computeStream(...)
。
额外信息
虽然这个 API 大部分是稳定的,但底层包(integral_isolates
)的实现尚未完全定型,未来会有更多特性加入,直到两个包都稳定下来。
完整示例Demo
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:use_isolate/use_isolate.dart';
void main() {
runApp(const MaterialApp(home: OuterWidget()));
}
class OuterWidget extends HookWidget {
const OuterWidget({Key? key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
final isTesting = useState<bool>(false);
return Scaffold(
appBar: AppBar(
title: InkWell(
child: const Text('插件示例应用'),
onTap: () {
isTesting.value = !isTesting.value;
},
),
),
body: isTesting.value
? const IsolateTestingWidget()
: const Center(child: Text("当前未测试")),
);
}
}
class IsolateTestingWidget extends HookWidget {
const IsolateTestingWidget({super.key});
static String _hello(_MethodInput input) {
sleep(input.delay);
return input.text;
}
static String _error(_MethodInput input) {
sleep(input.delay);
throw Exception('错误');
}
[@override](/user/override)
Widget build(BuildContext context) {
final isolate = useIsolate();
final tailoredIsolate = useTailoredIsolate<_MethodInput, String>(
backpressureStrategy: CombineBackPressureStrategy(
(oldData, newData) {
return _MethodInput(oldData.text + newData.text);
},
),
);
Future<String?> safeHello(_MethodInput input) async {
try {
return await tailoredIsolate.compute(_hello, input);
} catch (e) {
return null;
}
}
return ListView(
children: [
TextButton(
onPressed: () async {
final hi = await compute(_hello, _MethodInput("hi"));
print(hi);
},
child: const Text('运行 compute'),
),
TextButton(
onPressed: () async {
final hi =
_hello(_MethodInput("hi", delay: const Duration(seconds: 2)));
print(hi);
},
child: const Text('阻塞'),
),
TextButton(
onPressed: () async {
final hi = await isolate.compute(
_hello, _MethodInput("hi", delay: const Duration(seconds: 2)));
print(hi);
},
child: const Text('运行一次'),
),
TextButton(
onPressed: () async {
final yo = await isolate.compute(_hello, _MethodInput("yo"));
print(yo);
},
child: const Text('运行其他'),
),
TextButton(
onPressed: () async {
final hi = await isolate.compute(_hello, _MethodInput("hi"));
print(hi);
final yo = await isolate.compute(_hello, _MethodInput("yo"));
print(yo);
},
child: const Text('队列中运行两个'),
),
TextButton(
onPressed: () async {
isolate.compute(_hello, _MethodInput("hi")).then(print);
isolate
.compute(
_hello,
_MethodInput(
"yo",
delay: const Duration(milliseconds: 500),
),
)
.then(print);
},
child: const Text('并行运行两个,监听值'),
),
TextButton(
onPressed: () async {
final responses = await Future.wait(
[
isolate.compute(_hello, _MethodInput("hi")),
isolate.compute(
_hello,
_MethodInput("ho", delay: const Duration(milliseconds: 500)),
),
],
);
print(responses);
},
child: const Text('使用 Future.wait 并行运行两个'),
),
TextButton(
onPressed: () async {
final responses = await Future.wait(
[
safeHello(_MethodInput("hi")),
safeHello(
_MethodInput("ho", delay: const Duration(milliseconds: 500)),
),
safeHello(_MethodInput("hi")),
safeHello(_MethodInput("hi")),
],
);
print(responses);
},
child: const Text('使用尾调隔离'),
),
TextButton(
onPressed: () async {
final hi = await isolate.compute(_error, _MethodInput("hi"));
print(hi);
},
child: const Text('错误'),
),
const Center(child: CircularProgressIndicator()),
],
);
}
}
class _MethodInput {
final String text;
final Duration delay;
_MethodInput(
this.text, {
this.delay = const Duration(seconds: 1),
});
}
更多关于Flutter隔离执行插件use_isolate的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter隔离执行插件use_isolate的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter中使用use_isolate
插件来隔离执行代码的示例。use_isolate
插件允许你在Flutter应用中隔离执行耗时的操作,从而避免阻塞UI线程。
首先,你需要在你的pubspec.yaml
文件中添加use_isolate
依赖:
dependencies:
flutter:
sdk: flutter
use_isolate: ^x.y.z # 请替换为最新的版本号
然后运行flutter pub get
来获取依赖。
接下来,我们来看一个具体的代码示例,演示如何使用use_isolate
来隔离执行一个耗时的计算任务。
import 'package:flutter/material.dart';
import 'package:use_isolate/use_isolate.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('use_isolate Example'),
),
body: Center(
child: MyHomePage(),
),
),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String result = 'Calculating...';
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
result,
style: TextStyle(fontSize: 24),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () async {
setState(() {
result = 'Calculating...';
});
final computeResult = await computeIsolate(() {
// 模拟一个耗时的计算任务
return intensiveComputation();
});
setState(() {
result = 'Result: $computeResult';
});
},
child: Text('Start Computation'),
),
],
);
}
// 定义一个耗时的计算函数
int intensiveComputation() {
int sum = 0;
for (int i = 0; i < 100000000; i++) {
sum += i;
}
return sum;
}
}
// 使用use_isolate的computeIsolate函数替代dart:isolate的compute函数
Future<T> computeIsolate<T>(FutureOr<T> Function() fn) async {
final isolateResult = await compute(fn, null, debugLabel: 'Isolate #1');
return isolateResult as T;
}
注意:上面的代码示例中,computeIsolate
函数实际上并没有直接使用use_isolate
插件的特定功能,因为use_isolate
主要是为了解决在Flutter Web等不支持dart:isolate的环境中运行隔离代码的问题。在支持dart:isolate的环境中(如Flutter Mobile),你可以直接使用dart:isolate
库的compute
函数。
但是,如果你需要在Flutter Web上使用隔离执行,use_isolate
插件提供了一种替代方案。这里为了保持示例的通用性,我们仍然使用compute
函数。如果你需要在Web上运行,你应该查看use_isolate
的文档,了解如何正确配置和使用它。
对于Flutter Web,你可能需要像这样配置use_isolate
:
import 'package:use_isolate/use_isolate.dart';
void main() async {
// 配置use_isolate以支持Flutter Web
await configureIsolateBinaries();
runApp(MyApp());
}
确保在调用任何隔离执行代码之前配置好use_isolate
。
请根据你的具体需求调整上述代码,并查阅use_isolate
的官方文档以获取更多详细信息和高级用法。