Flutter并发执行插件flutter_isolate的使用
Flutter并发执行插件flutter_isolate的使用
FlutterIsolate简介
一个Dart isolate大致相当于一个独立的执行线程。在Flutter环境中,创建(“spawning”)一个isolate允许代码在主线程之外执行,这对于运行昂贵/长时间的任务非常重要,因为这些任务可能会阻塞UI。
然而,在生成的isolate中运行的代码通常无法与Flutter插件交互。这是由于平台插件脚手架和主应用程序isolate之间的紧密集成导致的。
FlutterIsolate插件通过引入FlutterIsolate
类解决了这个问题,该类是围绕创建isolate的平台API以及为在生成的isolate中运行的代码设置必要的绑定以与Flutter插件通信的封装。
FlutterIsolate API
方法 | Android | iOS | 描述 |
---|---|---|---|
FlutterIsolate.spawn(entryPoint, message) |
✅ | ✅ | 创建一个新的FlutterIsolate |
FlutterIsolate.pause() |
✅ | ✅ | 暂停正在运行的isolate |
FlutterIsolate.resume() |
✅ | ✅ | 恢复暂停的isolate |
FlutterIsolate.kill() |
✅ | ✅ | 终止一个isolate |
FlutterIsolate.killAll() |
✅ | ✅ | 终止所有当前运行的isolate |
FlutterIsolate.runningIsolates |
✅ | ✅ | 返回所有当前运行的isolate的ID |
flutterCompute(callback, message) |
✅ | ✅ | 创建一个新的FlutterIsolate,运行回调并返回结果 |
使用方法
创建FlutterIsolate
要创建一个FlutterIsolate,调用spawn
方法,并传递一个带有@pragma('vm:entry-point')
装饰器的顶层或静态函数:
import 'package:flutter_isolate/flutter_isolate.dart';
@pragma('vm:entry-point')
void someFunction(String arg) {
print("Running in an isolate with argument : $arg");
}
class SomeWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ElevatedButton(
child: Text('Run'),
onPressed: () {
FlutterIsolate.spawn(someFunction, "hello world");
},
);
}
}
执行单个任务
如果你只想创建一个isolate来执行单个任务(如Flutter的compute
方法),可以调用flutterCompute
:
@pragma('vm:entry-point')
Future<int> expensiveWork(int arg) async {
int result = 0;
// 假设这里有很多计算
for (var i = 0; i < 1000000000; i++) {
result += i;
}
return result;
}
Future<int> doExpensiveWorkInBackground() async {
return await flutterCompute(expensiveWork, 1);
}
在其他isolate中创建isolate
isolate也可以从其他isolate中创建:
import 'package:flutter_isolate/flutter_isolate.dart';
@pragma('vm:entry-point')
void isolate2(String arg) {
Timer.periodic(Duration(seconds:1),(timer)=>print("Timer Running From Isolate 2"));
}
@pragma('vm:entry-point')
void isolate1(String arg) async {
final isolate = await FlutterIsolate.spawn(isolate2, "hello2");
Timer.periodic(Duration(seconds:1),(timer)=>print("Timer Running From Isolate 1"));
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final isolate = await FlutterIsolate.spawn(isolate1, "hello");
Timer(Duration(seconds:5), (){print("Pausing Isolate 1");isolate.pause();});
Timer(Duration(seconds:10),(){print("Resuming Isolate 1");isolate.resume();});
Timer(Duration(seconds:20),(){print("Killing Isolate 1");isolate.kill();});
runApp(MyApp());
}
注意事项
- 入口点必须是一个顶层函数,并且需要加上
@pragma('vm:entry-point')
注解。 - 类级别的方法将不会工作,并会抛出异常。
- 忘记添加
@pragma('vm:entry-point')
注解会导致应用在发布模式下崩溃。 - 由于FlutterIsolate是由特定于平台的’view’支持的,因此事件循环不会在没有更多’用户’工作时终止,并且需要显式地使用
kill()
终止FlutterIsolates。
示例项目
下面是一个完整的示例项目,展示了如何使用flutter_isolate
插件来下载文件:
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_isolate/flutter_isolate.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_downloader/flutter_downloader.dart';
@pragma('vm:entry-point')
void isolate2(String arg) {
getTemporaryDirectory().then((dir) async {
print("isolate2 temporary directory: $dir");
await FlutterDownloader.initialize(debug: true);
FlutterDownloader.registerCallback(AppWidget.downloaderCallback);
final taskId = await FlutterDownloader.enqueue(
url:
"https://raw.githubusercontent.com/rmawatson/flutter_isolate/master/README.md",
savedDir: dir.path);
});
Timer.periodic(
Duration(seconds: 1), (timer) => print("Timer Running From Isolate 2"));
}
@pragma('vm:entry-point')
void isolate1(String arg) async {
await FlutterIsolate.spawn(isolate2, "hello2");
getTemporaryDirectory().then((dir) {
print("isolate1 temporary directory: $dir");
});
Timer.periodic(
Duration(seconds: 1), (timer) => print("Timer Running From Isolate 1"));
}
@pragma('vm:entry-point')
void computeFunction(String arg) async {
getTemporaryDirectory().then((dir) {
print("Temporary directory in compute function : $dir with arg $arg");
});
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await FlutterDownloader.initialize(debug: true);
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: AppWidget()));
}
}
class AppWidget extends StatelessWidget {
static void downloaderCallback(String id, int status, int progress) {
print("progress: $progress");
}
Future<void> _run() async {
print(
"Temp directory in main isolate : ${(await getTemporaryDirectory()).path}");
final isolate = await FlutterIsolate.spawn(isolate1, "hello");
Timer(Duration(seconds: 5), () {
print("Pausing Isolate 1");
isolate.pause();
});
Timer(Duration(seconds: 10), () {
print("Resuming Isolate 1");
isolate.resume();
});
Timer(Duration(seconds: 20), () {
print("Killing Isolate 1");
isolate.kill();
});
}
@override
Widget build(BuildContext context) {
return Column(crossAxisAlignment: CrossAxisAlignment.center, children: [
ElevatedButton(
child: Text('Spawn isolates'),
onPressed: _run,
),
ElevatedButton(
child: Text('Check running isolates'),
onPressed: () async {
final isolates = await FlutterIsolate.runningIsolates;
await showDialog(
builder: (ctx) {
return Center(
child: Container(
color: Colors.white,
padding: EdgeInsets.all(5),
child: Column(
children: isolates
.map((i) => Text(i))
.cast<Widget>()
.toList() +
[
ElevatedButton(
child: Text("Close"),
onPressed: () {
Navigator.of(ctx).pop();
})
])));
},
context: context);
},
),
ElevatedButton(
child: Text('Kill all running isolates'),
onPressed: () async {
await FlutterIsolate.killAll();
},
),
ElevatedButton(
child: Text('Run in compute function'),
onPressed: () async {
await flutterCompute(computeFunction, "foo");
},
),
]);
}
}
这个示例展示了如何使用flutter_isolate
插件来管理多个isolate,包括创建、暂停、恢复和终止isolate,以及检查当前运行的isolate。
更多关于Flutter并发执行插件flutter_isolate的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter并发执行插件flutter_isolate的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,flutter_isolate
是一个用于在 Flutter 中实现并发执行的插件,它利用 Dart 的 dart:isolate
库来创建独立的 Dart 执行环境,从而避免阻塞主 UI 线程。下面是一个使用 flutter_isolate
插件的简单示例代码,展示如何并发执行一些任务。
首先,确保在你的 pubspec.yaml
文件中添加 flutter_isolate
依赖:
dependencies:
flutter:
sdk: flutter
flutter_isolate: ^x.y.z # 请使用最新版本号
然后运行 flutter pub get
来安装依赖。
接下来是示例代码,展示如何使用 flutter_isolate
并发执行计算任务:
import 'package:flutter/material.dart';
import 'package:flutter_isolate/flutter_isolate.dart';
import 'dart:math';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Isolate Example'),
),
body: Center(
child: IsolateExample(),
),
),
);
}
}
class IsolateExample extends StatefulWidget {
@override
_IsolateExampleState createState() => _IsolateExampleState();
}
class _IsolateExampleState extends State<IsolateExample> {
String _result = 'Calculating...';
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Result: $_result'),
SizedBox(height: 20),
ElevatedButton(
onPressed: _calculate,
child: Text('Calculate'),
),
],
);
}
void _calculate() async {
setState(() {
_result = 'Calculating...';
});
// 使用 flutter_isolate 执行并发任务
final compute = Compute(entryPoint: _computeIntensiveTask);
final result = await compute.call(input: 42);
setState(() {
_result = 'Result: $result';
});
}
// 这是一个计算密集型任务的示例
static int _computeIntensiveTask(int input) {
// 模拟长时间计算
int result = 0;
for (int i = 0; i < 1000000; i++) {
result += pow(input.toDouble(), 2).toInt();
}
return result;
}
}
解释
-
依赖添加:在
pubspec.yaml
中添加flutter_isolate
依赖。 -
主应用结构:
MyApp
定义了应用的根结构,包含一个Scaffold
和一个居中的IsolateExample
组件。 -
IsolateExample 组件:这是一个有状态的组件,包含一个显示结果的文本和一个按钮。点击按钮时,调用
_calculate
方法。 -
_calculate 方法:
- 首先更新状态,显示“Calculating…”。
- 使用
Compute
类创建一个并发执行的环境,并指定_computeIntensiveTask
作为要执行的任务。 - 调用
compute.call
方法,并传入参数42
。这个方法会返回一个Future
,表示异步执行的结果。 - 当结果返回时,更新状态以显示计算结果。
-
_computeIntensiveTask 函数:这是一个计算密集型任务的示例,模拟一个长时间的计算过程。
注意事项
flutter_isolate
插件允许你在后台线程执行 Dart 代码,从而避免阻塞 UI 线程。这对于需要执行长时间计算或 I/O 操作的应用特别有用。- 请注意,由于 Dart 的 isolate 之间不能直接共享内存,因此需要通过消息传递机制来交换数据。
希望这个示例能够帮助你理解如何在 Flutter 中使用 flutter_isolate
插件进行并发执行。如果你有任何进一步的问题,欢迎继续提问!