pl_isolate 1.4.0
pl_isolate: ^1.4.0 copied to clipboard
A library to help with isolate communication.
pl_isolate #
https://github.com/user-attachments/assets/31985cfa-f3b4-440e-8459-fdc4f8dc7fe1
A powerful Flutter plugin that simplifies isolate communication and management.
Run heavy computations in separate isolates without blocking the UI thread.
โจ Features #
- ๐ Easy isolate lifecycle management
- ๐ Auto-dispose isolates after inactivity
- ๐ฏ Strongly-typed operations (
IsolateOperation<T>) - ๐งฉ One helper per operation (clean architecture friendly)
- โก Non-blocking UI for CPU-intensive work
- ๐ Built-in
IsolateManagerfor batching & concurrency control - ๐ Safe error propagation from isolate โ UI
- ๐ฆ Optimized data transfer (supports large payloads)
๐ฆ Installation #
Add this to your pubspec.yaml:
dependencies:
pl_isolate: ^1.0.0
Then run:
flutter pub get
๐ Quick Start #
1. Define an Operation #
Each task is represented by an IsolateOperation<T>.
import 'package:pl_isolate/pl_isolate.dart';
class CountableIsolateOperation extends IsolateOperation<int> {
@override
String get tag => 'count';
@override
Future<int> run(dynamic args) async {
if (args is int) {
int count = 0;
for (var i = 0; i < args; i++) {
count++;
}
return count;
}
return 0;
}
}
2. Create a Helper #
Each operation has its own IsolateHelper.
class CountIsolateHelper
extends IsolateHelper<dynamic, CountableIsolateOperation> {
@override
bool get isDartIsolate => false;
@override
String get name => 'CountIsolateHelper';
@override
bool get isAutoDispose => true;
CountIsolateHelper(super.operation);
}
โ Operation is injected via constructor โ NOT passed at runtime
3. Execute in UI #
class MyWidget extends StatefulWidget {
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
late final CountIsolateHelper _helper;
@override
void initState() {
super.initState();
_helper = CountIsolateHelper(CountableIsolateOperation());
}
Future<void> runTask() async {
try {
final result = await _helper.runIsolate(1000000);
print('Result: $result');
} catch (e) {
print('Error: $e');
}
}
@override
void dispose() {
_helper.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: runTask,
child: const Text('Run Task'),
);
}
}
๐ง Core Concept #
IsolateOperation โ Business logic
IsolateHelper โ Isolate lifecycle + execution
IsolateManager โ Queue + concurrency control
โ๏ธ Using IsolateManager (Advanced) #
Initialize #
final manager = IsolateManager.init(2, 12);
// 2 concurrent tasks, max 12 in queue
Add Tasks #
manager.addIsolateHelper(
CountIsolateHelper(CountableIsolateOperation()),
3000000,
);
manager.addIsolateHelper(
SumIsolateHelper(SumIsolateOperation()),
List.generate(500000, (i) => i),
);
Listen for Results #
manager.listenIsolateResult((result) {
if (result.errorMessage != null) {
print('โ ${result.name}: ${result.errorMessage}');
} else {
print('โ
${result.name}: ${result.result}');
}
});
Run Batch #
await manager.runAllInBatches();
Dispose #
manager.disposeAll();
๐งช Example Operations #
Sum Operation #
class SumIsolateOperation extends IsolateOperation<int> {
@override
String get tag => 'sum';
@override
Future<int> run(dynamic args) async {
if (args is List) {
int sum = 0;
for (final item in args) {
if (item is int) sum += item;
}
return sum;
}
return 0;
}
}
Delay Operation #
class DelayIsolateOperation extends IsolateOperation<String> {
@override
String get tag => 'delay';
@override
Future<String> run(dynamic args) async {
if (args is Map && args.containsKey('duration')) {
final duration = args['duration'] as int;
await Future.delayed(Duration(milliseconds: duration));
return 'Completed after ${duration}ms';
}
return 'Invalid arguments';
}
}
Error Operation #
class ErrorIsolateOperation extends IsolateOperation {
@override
String get tag => 'error';
@override
Future<dynamic> run(dynamic args) async {
throw Exception('This is a test error from isolate');
}
}
๐งฉ Best Practices #
1. One Helper = One Operation #
// โ
Good
CountIsolateHelper
SumIsolateHelper
// โ Avoid
GenericHelper
2. Do NOT pass operation into runIsolate #
// โ
Correct
helper.runIsolate(args);
// โ Wrong (old API)
helper.runIsolate(args, operation);
3. Always Dispose #
@override
void dispose() {
helper.dispose();
super.dispose();
}
4. Use Manager for Heavy Workloads #
- Few tasks โ use helper directly
- Many tasks โ use IsolateManager
5. Pass Serializable Data Only #
// โ
OK
int, String, List, Map
// โ Avoid
BuildContext, Function, Stream
โก Dart Isolate vs UI Isolate #
Regular Isolate (isDartIsolate = false) #
- Best performance
- No UI access
- Recommended for most cases
UI Isolate (isDartIsolate = true) #
- Needed for platform channels
- Slightly heavier
๐งฏ Troubleshooting #
Isolate not running? #
- Check helper initialization
- Verify
isDartIsolate
Serialization error? #
- Ensure data is transferable
Memory leak? #
- Forgot
dispose()
โค๏ธ Why pl_isolate? #
| Feature | compute() | pl_isolate |
|---|---|---|
| Reuse isolate | โ | โ |
| Queue system | โ | โ |
| Error handling | Basic | Advanced |
| Typed API | โ | โ |
| Batch execution | โ | โ |
๐ค Contributing #
Pull requests are welcome!
๐ License #
MIT License
๐ฌ Support #
https://github.com/NexPlugs/pl_isolate/issues
Made with โค๏ธ by NexPlugs