Need help maintaining only one Isolate executing
Closed this issue · 3 comments
I am using this package to get the palette from an Image when the user goes to the WallpaperScreen.
Code:
void computePalette(List<Object> args) async {
var image = args[0] as Uint8List;
var url = args[1] as String;
var port = args[2] as SendPort;
var img = Image.memory(image);
var palette = await PaletteGenerator.fromImageProvider(
img.image,
size: Size(300, 240),
maximumColorCount: 6,
);
List<int> colors = [];
palette.colors.forEach((element) => colors.add(element.value));
port.send([colors, url]);
}
class PaletteController extends GetxController {
FlutterIsolate? isolate;
void getPalette(WallpaperModel wall) async {
print("getting palette");
if (isolate != null) {
isolate!.kill();
print("isolate killed mid compute");
}
var cache = DefaultCacheManager();
File file = await cache.getSingleFile(wall.url);
var port = ReceivePort();
isolate = await FlutterIsolate.spawn(
computePalette,
[file.readAsBytesSync(), wall.url, port.sendPort],
);
port.listen((msg) {
List<Object> data = msg;
addColors(data, wall);
print("added palette for ${wall.name}");
isolate!.kill();
isolate = null;
port.close();
});
}
}
The Problem: My function seems to work when it is called once in 3 seconds. But when I call getPalette() rapidly (5 times in 3) seconds I get the following error in the console:
Error:
I/flutter (14144): getting palette for Soap
I/flutter (14144): getting palette for Green Impact
I/flutter (14144): isolate killed mid compute
I/flutter (14144): getting palette for Deep Dusky Canyon
I/flutter (14144): isolate killed mid compute
I/flutter (14144): added palette for Green Impact
E/MethodChannel#com.rmawatson.flutterisolate/control(14144): Failed to handle method call
E/MethodChannel#com.rmawatson.flutterisolate/control(14144): java.lang.NullPointerException: Attempt to read from field 'io.flutter.embedding.engine.FlutterEngine com.rmawatson.flutterisolate.IsolateHolder.engine' on a null object reference
E/MethodChannel#com.rmawatson.flutterisolate/control(14144): at com.rmawatson.flutterisolate.FlutterIsolatePlugin.onMethodCall(FlutterIsolatePlugin.java:211)
E/MethodChannel#com.rmawatson.flutterisolate/control(14144): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233)
E/MethodChannel#com.rmawatson.flutterisolate/control(14144): at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:85)
E/MethodChannel#com.rmawatson.flutterisolate/control(14144): at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:818)
E/MethodChannel#com.rmawatson.flutterisolate/control(14144): at android.os.MessageQueue.nativePollOnce(Native Method)
E/MethodChannel#com.rmawatson.flutterisolate/control(14144): at android.os.MessageQueue.next(MessageQueue.java:336)
E/MethodChannel#com.rmawatson.flutterisolate/control(14144): at android.os.Looper.loop(Looper.java:174)
E/MethodChannel#com.rmawatson.flutterisolate/control(14144): at android.app.ActivityThread.main(ActivityThread.java:7356)
E/MethodChannel#com.rmawatson.flutterisolate/control(14144): at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#com.rmawatson.flutterisolate/control(14144): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
E/MethodChannel#com.rmawatson.flutterisolate/control(14144): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:940)
E/flutter (14144): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: PlatformException(error, Attempt to read from field 'io.flutter.embedding.engine.FlutterEngine com.rmawatson.flutterisolate.IsolateHolder.engine' on a null object reference, null, java.lang.NullPointerException: Attempt to read from field 'io.flutter.embedding.engine.FlutterEngine com.rmawatson.flutterisolate.IsolateHolder.engine' on a null object reference
E/flutter (14144): at com.rmawatson.flutterisolate.FlutterIsolatePlugin.onMethodCall(FlutterIsolatePlugin.java:211)
E/flutter (14144): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233)
E/flutter (14144): at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:85)
E/flutter (14144): at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:818)
E/flutter (14144): at android.os.MessageQueue.nativePollOnce(Native Method)
E/flutter (14144): at android.os.MessageQueue.next(MessageQueue.java:336)
E/flutter (14144): at android.os.Looper.loop(Looper.java:174)
E/flutter (14144): at android.app.ActivityThread.main(ActivityThread.java:7356)
E/flutter (14144): at java.lang.reflect.Method.invoke(Native Method)
E/flutter (14144): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
E/flutter (14144): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:940)
E/flutter (14144): )
E/flutter (14144): #0 StandardMethodCodec.decodeEnvelope
E/flutter (14144): #1 MethodChannel._invokeMethod
E/flutter (14144): <asynchronous suspension>
E/flutter (14144):
As you can see from the 1st 6 lines of the error, line 5 says it killed the Isolate for Green Impact but line 6 says that the palette successfully computed for Green Impact (The names are of the images). I think the isolated are not getting killed correctly.
Is there any way I can achieve only 1 Isolate running at a time? It would be nice if flutterIsolate.kill() would let me know if the Isolate was killed or not.
After researching a bit. I tried to implement a single Isolate instead of trying to kill and create new Isolates each time. It was a bit hard to set up 2-way communication but now there are no errors. I just send the image to the Isolate via a port. If the isolate is already running, I set a while loop to poll a boolean variable which tells if the Isolate is free or not, if it is free then send the next Image in the pipeline. No more errors or performance issues now.
@ShreeyansB could you please share the solution code?
@ShreeyansB could you please share the solution code?
Check Here for the isolate code.
Also I am polling bool isIsolateComputing here (line 85) to check its value so that I wait for the previous palette computation to complete before computing a new palette otherwise I face lag.