tizen_interop_callbacks 0.4.0
tizen_interop_callbacks: ^0.4.0 copied to clipboard
Cross-thread callbacks for Tizen native APIs.
tizen_interop_callbacks #
A Flutter plugin to resolve issues related to the error message: Cannot invoke native callback outside an isolate.
This package is designed to be used with the tizen_interop package.
Similarly to tizen_interop, this package has no build time dependency on a specific Tizen profile or version.
Usage #
-
Add this package and
tizen_interopas dependencies in yourpubspec.yamlfile.dependencies: ffi: ^2.0.1 tizen_interop: ^0.5.0 tizen_interop_callbacks: ^0.4.0 -
In your Dart code, import the packages:
import 'dart:ffi'; import 'package:tizen_interop/6.0/tizen.dart'; import 'package:tizen_interop_callbacks/tizen_interop_callbacks.dart'; -
Instantiate the
TizenInteropCallbacksclass. This should be done in the root isolate - the thread where yourmain()is called.final callbacks = TizenInteropCallbacks(); -
Implement your callback in Dart and register it with
TizenInteropCallbacks:final callback = _callbacks.register<Void Function(Int32, Pointer<Void>, Pointer<Void>)>( 'device_changed_cb', Pointer.fromFunction(_batteryChanged), );The native function type to be used in
register<>()can be obtained by checking the definition of the related callback type - thedevice_changed_cbin this case. -
Pass the obtained callback pointer and user_data to the Native API function:
Warning
Both
interopCallbackandinteropUserDatamust be passed. The callback handling implementation relies on theinteropUserData. The only exceptions are a few callbacks that do not acceptuser_dataparameters.final ret = tizen.device_add_callback( device_callback_e.DEVICE_CALLBACK_BATTERY_CAPACITY, callback.interopCallback, callback.interopUserData, );
Note #
Using Separate Isolates for Non-Void Return Callbacks #
If your callback has a non-void return type, you must execute the Native API call in a separate isolate to avoid deadlocks. This is because blocking callbacks use synchronization mechanisms that can block the main isolate thread.
For a example of how to properly handle callbacks with return values, refer to getResolutions() code in example.
Future<void> getResolutions() async {
final callbacks = TizenInteropCallbacks();
final port = ReceivePort();
// Register callback with non-void return type (bool in this case)
final callback = callbacks.register<Bool Function(Int, Int, Pointer<Void>)>(
'camera_supported_preview_resolution_cb',
Pointer.fromFunction(_previewResolutionCallback, false),
userObject: _resolutions,
);
// Execute Native API call in separate isolate
await Isolate.spawn(_getResolutions, [port.sendPort, callback]);
await port.first;
callbacks.unregister(callback);
}
static void _getResolutions(List<Object> message) async {
final sendPort = message[0] as SendPort;
final callback = message[1] as RegisteredCallback<Bool Function(Int, Int, Pointer<Void>)>;
// Native API call with blocking callback
final ret = tizen.camera_foreach_supported_preview_resolution(
cameraHandle,
callback.interopCallback,
callback.interopUserData,
);
sendPort.send(null);
}
static bool _previewResolutionCallback(int width, int height, Pointer<Void> userData) {
// This callback executes in the main isolate
final resolutions = TizenInteropCallbacks.getUserObject<List<String>>(userData)!;
resolutions.add('$width x $height');
return true; // Return value
}