Ahsin Irshad
Senior Flutter Developer | Ex. Native Android Developer
Exploring Event and Method Channels in Flutter: A Comprehensive Guide | Jan, 2024
![Exploring Event and Method Channels in Flutter: A Comprehensive Guide | by Ritutosh Bhatia | Jan, 2024](https://ahsinirshad.com/wp-content/uploads/2024/01/1AEVKTeO82ixFQQUDJF4ukA.png)
Avoiding Plugin Dependency with Event Channels:
As a Flutter developer, you might want to reduce your reliance on plugins, and Event Channels provide an elegant solution for scenarios like retrieving device information. This approach helps maintain greater control over the codebase and can lead to a more lightweight application. I also set up an Event Channel for sending a string to Flutter
Add code in MainActivity.kt
class MainActivity : FlutterActivity() {
private val handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Set up an EventChannel for device information
val deviceEventChannel = EventChannel(
flutterEngine?.dartExecutor?.binaryMessenger,
DEVICE_EVENT_CHANNEL_NAME
)
// Send device information to Flutter
handler.postDelayed({
val deviceInfo = getDeviceInfo()
deviceEventChannel.setStreamHandler(object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, eventSink: EventChannel.EventSink) {
eventSink.success(deviceInfo)
}
override fun onCancel(arguments: Any?) {
// Handle cancellation
}
})
}, 1000)
// Set up an EventChannel for sending a string to Flutter
val stringEventChannel = EventChannel(
flutterEngine?.dartExecutor?.binaryMessenger,
STRING_EVENT_CHANNEL_NAME
)
// Example: send a string from native to Flutter every 2 seconds
handler.postDelayed({
sendStringToFlutter(“Hello from native!”)
// You can change the string or the frequency as needed
}, 2000)
}
private fun getDeviceInfo(): Map<String, Any> {
val deviceInfo = HashMap<String, Any>()
deviceInfo[“model”] = Build.MODEL
deviceInfo[“brand”] = Build.BRAND
deviceInfo[“version”] = Build.VERSION.RELEASE
// Add more information as needed
return deviceInfo
}
private fun sendStringToFlutter(message: String) {
val stringEventChannel = EventChannel(
flutterEngine?.dartExecutor?.binaryMessenger,
STRING_EVENT_CHANNEL_NAME
)
stringEventChannel.setStreamHandler(object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, eventSink: EventChannel.EventSink) {
eventSink.success(message)
}
override fun onCancel(arguments: Any?) {
// Handle cancellation
}
})
}
companion object {
private const val DEVICE_EVENT_CHANNEL_NAME = “deviceEventChannel”
private const val STRING_EVENT_CHANNEL_NAME = “stringEventChannel”
}
}
Call Event Channel in Ui
import 'package:event_channel_demo/core/constants/icon_constants.dart';
import 'package:event_channel_demo/core/constants/string_constants.dart';
import 'package:event_channel_demo/core/custom_elevated_button.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class EventChannelView extends StatefulWidget {
const EventChannelView({super.key});
@override
State<EventChannelView> createState() => _EventChannelViewState();
}
class _EventChannelViewState extends State<EventChannelView> {
static const EventChannel _deviceEventChannel =
EventChannel(‘deviceEventChannel’);
static const EventChannel _stringEventChannel =
EventChannel(‘stringEventChannel’);
Map<String, dynamic>? _deviceInfo;
String _stringFromNative = StringConstants.notReceivedString;
void _stopListeningAndClearEventChannelData() {
setState(() {
_deviceInfo = null;
_stringFromNative = StringConstants.notReceivedString;
});
}
void _sendDeviceInfoEvent() {
_deviceEventChannel.receiveBroadcastStream().listen((dynamic event) {
setState(() {
_deviceInfo = Map<String, dynamic>.from(event);
});
});
}
void _sendStringEvent() {
_stringEventChannel.receiveBroadcastStream().listen((dynamic event) {
setState(() {
_stringFromNative = event.toString();
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.black,
title: Text(StringConstants.eventChannel),
),
body: Column(
// mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
height: 100,
width: 100,
margin: const EdgeInsets.all(12),
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(AppIcons.bgImage),
alignment: Alignment.center,
fit: BoxFit.fill)),
)
],
),
SizedBox(height: MediaQuery.of(context).size.height*0.12),
if (_deviceInfo != null)
for (var entry in _deviceInfo!.entries)
Text(
‘${entry.key}: ${entry.value}’,
style: const TextStyle(fontSize: 16),
),
Text(
‘${StringConstants.stringFromNative}: $_stringFromNative’,
style: const TextStyle(fontSize: 16),
),
const SizedBox(height: 20),
CustomElevatedButton(title: StringConstants.getDeviceInfoNative,
onTap: _sendDeviceInfoEvent
),
const SizedBox(height: 10),
CustomElevatedButton(title: StringConstants.getStringNative,
onTap: _sendStringEvent
),
const SizedBox(height: 10),
CustomElevatedButton(title: StringConstants.clearData,
onTap: _stopListeningAndClearEventChannelData
),
],
),
);
}
}
Calculating the Sum with Method Channel:
To further showcase the usage of Method Channels, we’ve implemented a simple demo where Dart calls a native method to calculate the sum of two numbers. This provides a practical example of how Method Channels can be employed for specific tasks.
class MainActivity : FlutterActivity() {
private val handler = Handler(Looper.getMainLooper())
private val CHANNEL = "exampleMethodChannel"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
when (call.method) {
“getMessage” -> result.success(“Hello from Android!”)
“calculateSum” -> {
val a = call.argument<Int>(“a”) ?: 0
val b = call.argument<Int>(“b”) ?: 0
val sum = calculateSum(a, b)
result.success(sum)
}
else -> result.notImplemented()
}
}
}
private fun calculateSum(a: Int, b: Int): Int {
return a + b
}
}
Call Method Channel in Ui
import 'package:event_channel_demo/core/constants/icon_constants.dart';
import 'package:event_channel_demo/core/constants/string_constants.dart';
import 'package:event_channel_demo/core/custom_elevated_button.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class MethodChannelView extends StatefulWidget {
const MethodChannelView({super.key});
@override
State<MethodChannelView> createState() => _MethodChannelViewState();
}
class _MethodChannelViewState extends State<MethodChannelView> {
static const MethodChannel _methodChannel =
MethodChannel(‘exampleMethodChannel’);
int _result = 0;
Future<void> _calculateSum(int a, int b) async {
try {
final dynamic result = await _methodChannel
.invokeMethod(‘calculateSum’, {‘a’: a, ‘b’: b});
setState(() {
_result = result as int;
});
} on PlatformException catch (e) {
setState(() {
_result = 0;
});
if (kDebugMode) {
print(‘Error: ${e.message}’);
}
}
}
void _stopListeningAndClearMethodChannelData() {
setState(() {
_result = 0;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.black,
title: Text(StringConstants.methodChannel),
),
body: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
height: 100,
width: 100,
margin: const EdgeInsets.all(12),
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(AppIcons.bgImage),
alignment: Alignment.center,
fit: BoxFit.fill)),
)
],
),
SizedBox(height: MediaQuery.of(context).size.height*0.15),
Text(
‘${StringConstants.result}: $_result’,
style: const TextStyle(fontSize: 16),
),
const SizedBox(height: 10),
CustomElevatedButton(title: ‘${StringConstants.calculateSum} (10 + 20)’,
onTap: () => _calculateSum(10, 20),
),
const SizedBox(height: 10),
CustomElevatedButton(title: ‘${StringConstants.calculateSum} (5 + 7)’,
onTap: () => _calculateSum(5, 7),
),
const SizedBox(height: 10),
CustomElevatedButton(title: StringConstants.clearData,
onTap: _stopListeningAndClearMethodChannelData,
),
],
),
);
}
}
#Exploring #Event #Method #Channels #Flutter #Comprehensive #Guide #Ahsin #Irshad