Threading topic
Threading considerations
Unlike method channels, JNIgen uses FFI calls. This means that the calls happen on the calling thread.
Dart callbacks are executed on the isolate where they were created. This means the Dart isolate remains active until the associated Java objects are garbage collected by the JVM.
Java calls Dart callbacks directly when both are on the same thread. If they are on different threads, Java sends a message to the Dart isolate and waits for a response. However, you can configure void-returning callbacks to avoid waiting, as they don't produce a return value.
Deadlocks
When implementing Java/Kotlin interfaces in Dart, it is possible to create
deadlocks. Suppose we have created an object that implements Runnable
in Dart
in the main isolate. This means that the code will always be run on the platform
thread.
// Dart
final runnableFromDart = Runnable.implement(
$Runnable(run: () => print('hello'))
);
If Java creates a second thread from the platform thread and calls
runnableFromDart.run()
from that thread and then attempts to join or
synchronize with the main thread, it will cause a deadlock.
This is because the body of the runnableFromDart
needs to be run on the
platform thread, so JNIgen waits until platform thread is available. However in
this setting the platform thread will not be available until
runnableFromDart.run
is executed.
If the callback does not need to be blocking, making it a listener solves this issue:
// Dart
final runnableFromDart = Runnable.implement($Runnable(
run: () => print('hello'),
run$async: true,
));
Of course, only void-returning methods can be non-blocking.
Calling thread restricted APIs
When developing for Flutter Android, certain APIs can be thread-restricted to the platform thread which is currently different than the Flutter's UI thread.
These two threads will be merged in the near future.
Until then you can wrap your calls with runOnPlatformThread
which is available
in dart:ui
.
Dart-standalone
On Dart-standalone, call Jni.setDylibsDir
in each new isolate, since each
isolate loads the dynamic libararies separately.
Libraries
- jnigen Java Differences Lifecycle Threading Interface Implementation
- This library exports a high level programmatic API to jnigen, the entry point of which is runJniGenTask function, which takes run configuration as a JniGenTask.