Skip to content

EventChannel does not work inside an isolate #30332

@softkot

Description

@softkot

For some reason EventChannel does not listen for an events emitted from platform side if it runs within FlutterNativeView.runFromBundle isolate started as a part of android background service.

Keypoints

Plugin-like class implements simple MethodChannel and EventChannel.

Calling MethodChannel.invokeMethod emits counter on EventChannel.

class Plugin(registry: PluginRegistry, val label: String) {
    @Volatile
    private var sink: EventChannel.EventSink? = null
    private val counter = AtomicInteger()

    init {
        registry.registrarFor("isolate").apply {
            MethodChannel(messenger(), "methods").setMethodCallHandler { methodCall, result ->
                sink?.success(hashMapOf(
                        "label" to label,
                        "counter" to counter.incrementAndGet()
                ))
                Log.d("PLUGIN", "Call ${methodCall.method} from $label")
                result.success(null)
            }
            EventChannel(messenger(), "events").setStreamHandler(object : EventChannel.StreamHandler {
                override fun onListen(p0: Any?, s: EventChannel.EventSink?) {
                    sink?.endOfStream()
                    sink = s
                }

                override fun onCancel(p0: Any?) {
                    sink?.endOfStream()
                    sink = null
                }
            })
        }

    }
}

Dart handler use MethodChannel and EventChannel to periodicaly call method and waiting any data on event channel to arrive.

void platformChannels() {
  print("Start platform channels test");
  MethodChannel pluginMethods = const MethodChannel('methods');
  EventChannel pluginEvents = const EventChannel('events');
  pluginEvents.receiveBroadcastStream().listen((data) {
    print(data);
  });
  Timer.periodic(Duration(seconds: 1), (timer) {
    pluginMethods.invokeMethod("tick", {});
  });
}

Main activity startup code register the Plugin-like class and start android service

Plugin(this,"Activity")
startService(Intent(this,PluginService::class.java))

Service startup code create new dart isolate with backgound FlutterNativeView with dart entrypoint set to platformChannels on main.dart

override fun onCreate() {
        super.onCreate()
        FlutterMain.startInitialization(this)
        FlutterMain.ensureInitializationComplete(this, null)
        bgView = FlutterNativeView(this, true)
        Plugin(bgView.pluginRegistry, "Service")
        bgView.runFromBundle(FlutterRunArguments().apply {
            bundlePath = FlutterMain.findAppBundlePath(this@PluginService)
            entrypoint = "platformChannels"
        })
    }

Finnaly when app is runnung only Activity bound dart code works as expected. Service bound dart code never prints data on listen closure.

Steps to Reproduce

git clone https://github.com/softkot/flutter_isolate
cd flutter_isolate

Connect android device or an emulator and run

flutter run

Application logs

produced

D/PLUGIN  (25664): Call tick from Service
D/PLUGIN  (25664): Call tick from Activity
I/flutter (25664): {label: Activity, counter: 2}
D/PLUGIN  (25664): Call tick from Service
D/PLUGIN  (25664): Call tick from Activity
I/flutter (25664): {label: Activity, counter: 3}
D/PLUGIN  (25664): Call tick from Service
D/PLUGIN  (25664): Call tick from Activity
I/flutter (25664): {label: Activity, counter: 4}
D/PLUGIN  (25664): Call tick from Service
D/PLUGIN  (25664): Call tick from Activity
I/flutter (25664): {label: Activity, counter: 5}

expected

D/PLUGIN  (25664): Call tick from Service
D/PLUGIN  (25664): Call tick from Activity
I/flutter (25664): {label: Activity, counter: 2}
I/flutter (25664): {label: Service, counter: 2}
D/PLUGIN  (25664): Call tick from Service
D/PLUGIN  (25664): Call tick from Activity
I/flutter (25664): {label: Activity, counter: 3}
I/flutter (25664): {label: Service, counter: 3}
D/PLUGIN  (25664): Call tick from Service
D/PLUGIN  (25664): Call tick from Activity
I/flutter (25664): {label: Activity, counter: 4}
I/flutter (25664): {label: Service, counter: 4}
D/PLUGIN  (25664): Call tick from Service
D/PLUGIN  (25664): Call tick from Activity
I/flutter (25664): {label: Activity, counter: 5}
I/flutter (25664): {label: Service, counter: 5}

Flutter doctor

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.2.1, on Linux, locale ru_RU.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
[✓] Android Studio (version 3.3)
[✓] IntelliJ IDEA Ultimate Edition (version 2019.1)
[✓] Connected device (1 available)

• No issues found!

Metadata

Metadata

Assignees

No one assigned

    Labels

    engineflutter/engine related. See also e: labels.frameworkflutter/packages/flutter repository. See also f: labels.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions