Flutter后台工作线程插件flt_worker_nullsafety的使用
Flutter后台工作线程插件flt_worker_nullsafety的使用
flt_worker_nullsafety
插件允许你在专用的隔离(isolate)中调度并执行用Dart编写的后台任务。在Android上,它利用了WorkManager
API,在iOS 13.0+上则使用了BackgroundTasks
API。
后台处理适用于时间较长的任务,如下载/上传离线数据、拟合机器学习模型等。你可以使用该插件来安排这些任务。当系统决定运行任务时,会启动并运行一个预注册的Dart Worker。
集成
在 pubspec.yaml
文件中添加依赖:
dependencies:
flt_worker_nullsafety: ^0.1.0
一个Worker在单独的Flutter引擎实例中运行。如果在Worker中需要任何插件,则必须重新注册它们。以下是一个例子,展示了如何为后台隔离注册 path_provider
插件。
iOS
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// 设置回调以向无头引擎实例注册所有插件
FltWorkerPlugin.registerPlugins = ^(NSObject<FlutterPluginRegistry> *registry) {
[FLTPathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTPathProviderPlugin"]];
};
...
}
Android
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
// 设置回调以向无头引擎实例注册所有插件
FltWorkerPlugin.registerPluginsForWorkers = registry -> {
io.flutter.plugins.pathprovider.PathProviderPlugin.registerWith(
registry.registrarFor("io.flutter.plugins.pathprovider.PathProviderPlugin"));
return null;
};
}
需要注意的是,flt_worker_nullsafety
插件本身总是可用的,因此无需再次注册。
如果你正在开发iOS应用,所有任务标识符必须在提交任何 BGTaskRequest
之前进行注册。
在 Info.plist
文件中添加以下行:
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>com.example.counter_task</string>
<string>dev.example.task2</string>
...
</array>
使用
初始化与工作调度器
在可以调度后台任务之前,必须向插件注册Worker回调:
import 'package:flt_worker_nullsafety/flt_worker.dart';
void main() {
runApp(MyApp());
initializeWorker(worker);
}
// 请注意,回调必须是一个顶级或静态函数
worker
函数作为所有后台任务的调度器,你可以根据工作负载的数据调用不同的函数,并返回一个 Future
,以便插件可以在工作完成时通知系统调度器。
Future<void> worker(WorkPayload payload) {
if (payload.tags.contains('download')) {
return _fetchData();
} else if (...) {
...
} else {
return Future.value();
}
}
/// 缓存数据用于离线使用
Future<void> _fetchData() async {
// 获取数据并更新本地存储
}
调度工作
你可以使用 enqueueWorkIntent
函数来调度后台 WorkIntent
,如下所示:
enqueueWorkIntent(WorkIntent(
identifier: 'counter',
initialDelay: Duration(seconds: 59),
input: <String, dynamic>{
'counter': counter,
},
));
名称 WorkIntent
被选择是为了避免与 WorkManager
API 中的术语 WorkRequest
发生冲突。
请参阅文档及示例应用程序,了解如何调度不同类型的后台工作。
高级API与低级API
后台处理策略和API在Android和iOS平台上有很大差异。flt_worker_nullsafety
插件提供了统一且简化的API,适用于一般任务,如上面的例子所示。
然而,为了充分利用每个平台的后台处理功能,你可能需要考虑使用低级的平台特定API。
例如,在Android设备上,你可以使用 WorkManager
API 来调度周期性工作:
import 'package:flt_worker_nullsafety/android.dart';
Future<void> _startPolling() async {
await cancelAllWorkByTag('tag'); // 取消之前的任务
await enqueueWorkRequest(const PeriodicWorkRequest(
repeatInterval: Duration(hours: 4),
flexInterval: Duration(minutes: 5),
tags: ['tag'],
constraints: WorkConstraints(
networkType: NetworkType.connected,
storageNotLow: true,
),
backoffCriteria: BackoffCriteria(
policy: BackoffPolicy.linear,
delay: Duration(minutes: 1),
),
));
}
或者在iOS 13.0+ 上使用 BackgroundTasks
API:
import 'package:flt_worker_nullsafety/ios.dart';
void _increaseCounter(int counter) {
submitTaskRequest(BGProcessingTaskRequest(
'com.example.counter_task',
earliestBeginDate: DateTime.now().add(Duration(seconds: 10)),
requiresNetworkConnectivity: false,
requiresExternalPower: true,
input: <String, dynamic>{
'counter': counter,
},
));
}
限制
这是一个新库,需要注意的一些限制包括:
- 它依赖于
BackgroundTasks
框架,这意味着它不适用于iOS 13.0之前的版本。 - 对于Android平台,
WorkManager
的高级功能(如链式工作)尚未支持。
示例代码
以下是完整的示例代码,展示了如何使用 flt_worker_nullsafety
插件来调度后台任务。
示例代码
import 'dart:io';
import 'package:flt_worker_nullsafety/flt_worker.dart';
import 'package:flutter/material.dart';
import 'background_tasks_btc_prices.dart';
import 'background_tasks_counter.dart';
import 'btc_prices.dart';
import 'counter.dart';
import 'work_manager_btc_prices.dart';
import 'work_manager_counter.dart';
import 'worker.dart';
/// 后台处理示例。
///
/// 强制启动iOS后台任务:
/// ```
/// e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.example.btc_prices_task"]
/// e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.example.counter_task"]
/// e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.example.task1"]
/// e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"dev.example.task2"]
/// ```
///
/// > 查看 [iOS文档](https://developer.apple.com/documentation/backgroundtasks/starting_and_terminating_tasks_during_development)
void main() {
runApp(MyApp());
initializeWorker(worker);
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) => MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Worker 示例'),
),
body: Builder(
builder: (context) => SingleChildScrollView(
child: Container(
padding: const EdgeInsets.symmetric(vertical: 48, horizontal: 32),
child: DefaultTextStyle(
textAlign: TextAlign.center,
style: const TextStyle(),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text('高级API示例',
style: TextStyle(
fontSize: 14,
color: Colors.black45,
),
),
const SizedBox(height: 16),
TextButton(
child: const Text('计数器'),
onPressed: () => Navigator.push(context, MaterialPageRoute(
builder: (_) => Counter(),
)),
),
TextButton(
child: const Text('比特币价格轮询'),
onPressed: () => Navigator.push(context, MaterialPageRoute(
builder: (_) => BtcPrices(),
)),
),
Padding(
padding: const EdgeInsets.only(top: 48, bottom: 16),
child: const Text('低级平台特定API示例',
style: TextStyle(
fontSize: 14,
color: Colors.black45,
),
),
),
...(Platform.isAndroid ? _workManagerExamples(context) : _bgTasksExamples(context)),
],
),
),
),
),
),
),
);
}
List<Widget> _workManagerExamples(BuildContext context) => [
TextButton(
child: const Text('计数器\n(一次性任务请求)'),
onPressed: () => Navigator.push(context, MaterialPageRoute(
builder: (_) => WorkManagerCounter(),
)),
),
TextButton(
child: const Text('比特币价格轮询\n(周期性任务请求)'),
onPressed: () => Navigator.push(context, MaterialPageRoute(
builder: (_) => WorkManagerBtcPrices(),
)),
),
];
List<Widget> _bgTasksExamples(BuildContext context) => [
TextButton(
child: const Text('计数器\n(处理任务请求)'),
onPressed: () {
Navigator.push(context, MaterialPageRoute(
builder: (_) => BackgroundTasksCounter(),
));
},
),
TextButton(
child: const Text('比特币价格轮询\n(应用刷新任务请求)'),
onPressed: () {
Navigator.push(context, MaterialPageRoute(
builder: (_) => BackgroundTasksBtcPrices(),
));
},
),
];
更多关于Flutter后台工作线程插件flt_worker_nullsafety的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter后台工作线程插件flt_worker_nullsafety的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
flt_worker
是一个用于在 Flutter 中创建和管理后台工作线程的插件,支持空安全(null safety)。它允许你在后台执行耗时的任务,而不会阻塞 UI 线程,从而提高应用的性能和响应速度。
安装
首先,在 pubspec.yaml
文件中添加 flt_worker
插件的依赖:
dependencies:
flutter:
sdk: flutter
flt_worker: ^1.0.0
然后运行 flutter pub get
来安装依赖。
基本使用
1. 导入插件
import 'package:flt_worker/flt_worker.dart';
2. 创建并启动工作线程
void startWorker() async {
// 创建一个工作线程
final worker = Worker();
// 启动工作线程并传递一个任务
worker.run((message) {
// 这里是在后台线程中执行的代码
print('Message from main thread: $message');
// 模拟耗时操作
Future.delayed(Duration(seconds: 2), () {
print('Task completed in background thread');
});
// 返回结果给主线程
return 'Task completed';
}).then((response) {
// 这里是在主线程中接收到的结果
print('Response from worker: $response');
});
// 发送消息给工作线程
worker.send('Hello from main thread');
}
3. 停止工作线程
void stopWorker() {
worker.dispose();
}
详细说明
- Worker:
Worker
类用于创建和管理一个后台工作线程。 - run:
run
方法用于启动工作线程,并传递一个回调函数。这个回调函数将在后台线程中执行。 - send:
send
方法用于从主线程向工作线程发送消息。 - dispose:
dispose
方法用于停止和释放工作线程的资源。
示例
以下是一个完整的示例,展示了如何使用 flt_worker
插件在后台执行耗时任务:
import 'package:flutter/material.dart';
import 'package:flt_worker/flt_worker.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: WorkerExample(),
);
}
}
class WorkerExample extends StatefulWidget {
[@override](/user/override)
_WorkerExampleState createState() => _WorkerExampleState();
}
class _WorkerExampleState extends State<WorkerExample> {
late Worker worker;
[@override](/user/override)
void initState() {
super.initState();
worker = Worker();
}
void startWorker() async {
worker.run((message) {
print('Message from main thread: $message');
// 模拟耗时操作
Future.delayed(Duration(seconds: 2), () {
print('Task completed in background thread');
});
return 'Task completed';
}).then((response) {
print('Response from worker: $response');
});
worker.send('Hello from main thread');
}
[@override](/user/override)
void dispose() {
worker.dispose();
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Worker Example'),
),
body: Center(
child: ElevatedButton(
onPressed: startWorker,
child: Text('Start Worker'),
),
),
);
}
}