How to call a platform code from an isolate in flutter? - flutter

I know these libraries flutter_isolate and isolate_handler exist that support doing these but I couldn't find any method to call platform specific codes from inside of them. Can someone show any example of how it's done ?

My answer might not answer to your question directly but I was facing the same situation.
I was working on this to run a computing intensive task avoiding UI lagging. After a long research, no, you cannot run Platform from other isolates rather than the main one.
Instead of making and running the native code on another isolate, let's make the native code run in background instead with TaskQueue.
Channels and platform threading
The example code in the above link is using onAttachedToEngine, you can check it out. However, I was using is configureFlutterEngine so I have to figure out a little bit until I found a solution that I need binaryMessenger to make it working. Luckily it can called from flutterEngine too!
This is the example code of when using configureFlutterEngine
class MainActivity: FlutterFragmentActivity() {
val MOBILE_SDK_CHANNEL = "com.example.app/flutter"
override fun configureFlutterEngine(#NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
super.configureFlutterEngine(flutterEngine)
val taskQueue = flutterEngine.dartExecutor.binaryMessenger.makeBackgroundTaskQueue()
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, MOBILE_SDK_CHANNEL,
StandardMethodCodec.INSTANCE, taskQueue).setMethodCallHandler { call, result ->
// TODO : Do implementation here
when (call.method) {
"example_method" -> {
// success
// result.success(data)
}
else -> result.notImplemented()
}
}
}
}
With taskQueue the native code will be ready to run in background.
Future<void> getData() async {
if (Platform.isAndroid) {
const platform = MethodChannel("com.example.app/flutter");
var data = await platform.invokeMethod("example_method");
// data is ready to use and non-blocked the UI thread
return data
}
}
The native code now runs in non-blocking manner, no more UI lag. :)

Related

Flutter - how to cancel a SSE Stream

Hey I cant figure out how to cancel an SSE Stream in my flutter app.
I am using this package to use SSE in my app: https://pub.dev/packages/sse_channel
I feel like it has a major lack in the documentation.
The SSE works fine just don't know how to stop it with a function.
Im using this to start the SSE
channel = SseChannel.connect(Uri.parse(dotenv.env['BASE_URL'] + '/sse/rn-updates'));
and
channel.stream.listen((message) { code... and some other stuff }
that part works but I don't know how to close it.
Tried stuff like this
static void cancelStream() {
if (channel != null)
channel.sink.close()
}
You should create a global var in your class
StreamSubscription? stream;
and assign it to this variable
stream = channel.stream.listen((message) { code... and some other stuff }
and you can use this code to cancel stream
stream?.cancel();

Alternative ways to receive result from async/await on Main Thread for Swift

Recently, I ran into a problem where I got a warning for updating UI on background task.
func didInit() async {
listOfTodo = await interactor.getTodos()
}
I tried to wrap the function body inside DispatchQue.main.async {}, but I got an error.
I then found a solution which I have to put #MainActor on top of my function, but I feel like there are other solutions that would make more sense, or this is the only way to work with async/await on Main Thread?
#MainActor
func didInit() async {
listOfTodo = await interactor.getTodos()
}
You're approaching this backwards. If interactor.getTodos() must be run on the main actor, then it should be marked #MainActor, not the caller. But if didInit is logically "a UI-updating method," then it's fine to mark it #MainActor as well.
Or you can use MainActor.run {...} to manually move this one call to the main actor. It all comes down to what you mean to express.
A better approach would be to create a function which takes responsibility of updating UI, something like below
#MainActor
func updateUI() async {
// Code to update your UI
}
Call this function inside your task function like below
func didInit() {
Task.detached { // or specify a priority with Task.detached(priority: .background)
listOfTodo = interactor.getTodos()
await self.updateUI()
}
}
Note: Code is not tested on Xcode so may be require some changes

is it possible to stream mjpeg video from native Kotlin to Flutter?

I have video stream in mjpeg format, so I have read and implmented a lot of ways to work with it, but anything of these ways don't meet my requirments (also I was using webView packages, but now we should implement changing screen oreintation feature and webView dosen't have such thing, so I am using Hero animation to make it works, but in that case my urls with video stream open twice. It dosen't work because it has limitation: only one user can watch stream, in other cases stream will be closed).
So I have found the way to play mjepeg video using Kotlin, and read bout MethodChannel in Flutter, I implemented almost everything as it was said in docs, but it still dosen't work.
Native code:
class MainActivity: FlutterActivity() {
private val channel = "com.example.my_app"
private var view: MjpegView? = null
override fun configureFlutterEngine(#NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, channel).setMethodCallHandler {
call, result ->
if(call.method == "Video") {
view = findViewById(R.id.mjpegid)
view!!.isAdjustHeight = true
view!!.mode1 = MjpegView.MODE_FIT_WIDTH
view!!.setUrl("http://videos/videos/LiveViewCamera")
view!!.isRecycleBitmap1 = true
result.success("it successed!")
}
else {
result.notImplemented()
}
}
}
}
in Flutter:
final channel = MethodChannel('com.example.my_app');
String videos = '';
Future getVideoFromNative() async {
videos = await channel.invokeMethod('Video');
print(videos);
print('are you hehe?');
setState(() {});
}
Got this error:
E/MethodChannel#com.example.rosysk_nano_cleaned(17621): Failed to handle method call
E/MethodChannel#com.example.rosysk_nano_cleaned(17621): java.lang.NullPointerException
When I open it in pure Kotlin app, my video and code works perfectly fine

Flutter Riverpod design pattern (inhibit garbage collection)

I've written a Swift/IOS package to externalize and standardize all of my Social/Federated/Firebase authentication boilerplate (both SDK's and UI). I've taken it upon myself to port this to Flutter as a learning exercise ... but to also allow custom UI to be passed-in via config.
Since I'm new to Flutter & Riverpod, I'm afraid I'm making some serious mistake & want to get feedback from you experts before I go too deep.
The package is called "Social Login Helper" or SLH, and this is the public API I desire:
runApp(
slh.authStateBuilder(
builder: (authStatus) {
switch (authStatus.stage) {
case SlhResultStage.initializing:
return SplashScreen();
case SlhResultStage.unauthenticated:
// using Riverpod and Nav 2.0
return slh.authFlowUi;
case SlhResultStage.authenticated:
return ExampleApp(appKey, authStatus, slh.logoutCallback);
case SlhResultStage.wantsAnnonOnlyFeatures:
return ExampleApp(appKey, null, slh.startAuthCallback);
case SlhResultStage.excessiveFailures: // restart the app
return TotalFailure();
}
},
),
);
As you can see from the above, the State/Stream builder at root must never be garbage collected or purged. I'm unclear if and when Riverpod will dispose my provider, or if Dart itself will collect objects that must remain immortal. I'm also unsure whether to use a StreamProvider or a State provider??
As you can see below, I've created an intentional memory-leak (deadlock) to guard me. I'm sure it's an anti-pattern, but being novice, I'm not sure how else to guarantee immortality.
All guidance and explicit feedback would be most welcome.
class LivingAuthState extends StateNotifier<SlhResultStage> {
// create deadly embrace to prevent this from ever being collected
_Unpurgeable _up;
LivingAuthState() : super(SlhResultStage.initializing) {
//
final StreamProvider<SlhResultStage> rssp =
StreamProvider<SlhResultStage>((ref) {
return this.stream.asBroadcastStream();
});
_up = _Unpurgeable(this, rssp);
// how do I keep rssp from ever being collected??
}
StreamProvider<SlhResultStage> get authStatusStream => _up.rssp;
void logout() {
this.state = SlhResultStage.unauthenticated;
}
void restartLogin() {
this.state = SlhResultStage.unauthenticated;
}
}
class _Unpurgeable {
final LivingAuthState _aliveState;
final StreamProvider<SlhResultStage> rssp;
_Unpurgeable(this._aliveState, this.rssp);
}
One improvement I'd like to see in the Riverpod documentation is clarity on HOW LONG a provider will live, WITHOUT an active listener, before it will self-dispose / garbage-collect.
Ah, it looks like I can subclass AlwaysAliveProviderBase() to achieve the same goal ... I'll experiment with this.
Move your provider final to the top level. Riverpod providers are top-level final variables.
Also remember to wrap your app in the riverpod provider.

Is there anyway in Kotlin something like Dart's Completer behavior?

I'm creating plugin for flutter. And face a issue from Android native.
I'm using Kotlin for Android and want to use value from platform channel from Flutter.
It's hard to explain in English. Here's a code.
fun Foo(): Any? {
methodChannel.invokeMethod(
"method",
null,
object : ErrorLogResult("tag") {
override fun success(result: Any?) {
super.success(result)
// Get result.
}
})
// return result from result callback after callback is done.
}
It can be like below in dart code.
Future<dynamic> Foo() async {
final completer = Completer();
someFunctionWithCallback((result) {
completer.complete(result);
});
return completer.future;
}
Old question, but maybe someone will come across this issue, as I had.
Yes, there is something similar: CompletableDeferred
Example pseudocode:
#Volatile
private var completableMeetingService = CompletableDeferred<MeetingService>()
// we want to join meeting, but have to wait for initialization
completableMeetingService.await().joinMeetingWithParams
// completing deffered in some listener
completableMeetingService.complete(zoomSDK.meetingService)