Flutter 事件通道演示
使用事件通道通过原生 (Java) 获取流数据到 Flutter。
演示
20220830_105813.mp4
简要代码解释
原生 (Java) – 解析器
一个命名的通道,用于通过事件流与平台插件进行通信。
流设置请求在发送前被编码为二进制,接收到的二进制事件和错误会被解码为 Dart 值。使用的 MethodCodec 必须与平台插件使用的 MethodCodec 兼容。这可以通过在平台端创建此通道的 EventChannel 对应物来实现。发送和接收的事件的 Dart 类型是动态的,但只能使用指定 MethodCodec 支持的值。
通道的逻辑标识由其名称决定。相同名称的通道会相互干扰通信。
参见:flutter.dev/platform-channels/
public static final String STREAM = "com.chamelalaboratory.demo.flutter_event_channel/eventChannel";
private EventChannel.EventSink attachEvent;
创建一个可运行的线程,该线程将每 200 毫秒递增计数器的值。最大迭代次数为 100。递增的计数器值将每 200 毫秒除以最大数量,因为我们需要 LinearProgressIndicator 的值。
private int count = 1;
private Handler handler;
private final Runnable runnable = new Runnable() {
@Override
public void run() {
int TOTAL_COUNT = 100;
if (count > TOTAL_COUNT) {
attachEvent.endOfStream(); // ends the stream
} else {
// we need to values for LinearProgressIndicator
double percentage = ((double) count / TOTAL_COUNT);
attachEvent.success(percentage);
Log.w(TAG_NAME, "\nParsing From Native: " + percentage);
}
count++;
handler.postDelayed(this, 200);
}
};
添加一个新的平台通道以从原生代码流式传输数据比我预期的要容易得多。只需实现 StreamHandler 接口并发出事件即可。
new EventChannel(Objects.requireNonNull(getFlutterEngine()).getDartExecutor(), STREAM).setStreamHandler(
new EventChannel.StreamHandler() {
@Override
public void onListen(Object args, final EventChannel.EventSink events) {
Log.w(TAG_NAME, "Adding listener");
attachEvent = events;
count = 1;
handler = new Handler();
runnable.run();
}
@Override
public void onCancel(Object args) {
Log.w(TAG_NAME, "Cancelling listener");
handler.removeCallbacks(runnable);
handler = null;
count = 1;
attachEvent = null;
System.out.println("StreamHandler - onCanceled: ");
}
}
);
Flutter – 接收器
Dart 内置了对流的支持,EventChannel 利用此支持来告知原生代码何时开始发出事件以及何时停止。只需收听平台通道流即可从原生端启动事件发射器。完成时取消订阅即可。
static const stream = EventChannel('com.chamelalaboratory.demo.flutter_event_channel/eventChannel');
late StreamSubscription _streamSubscription;
double _currentValue = 0.0;
void _startListener() {
_streamSubscription = stream.receiveBroadcastStream().listen(_listenStream);
}
void _cancelListener() {
_streamSubscription.cancel();
setState(() {
_currentValue = 0;
});
}
void _listenStream(value) {
debugPrint("Received From Native: $value\n");
setState(() {
_currentValue = value;
});
}
完整代码 (Java)
package com.chamelalaboratory.demo.flutter_event_channel;
import android.os.Bundle;
import android.os.Handler;
import java.util.Objects;
import io.flutter.Log;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.plugin.common.EventChannel;
public class MainActivity extends FlutterActivity {
public static final String STREAM = "com.chamelalaboratory.demo.flutter_event_channel/eventChannel";
private EventChannel.EventSink attachEvent;
final String TAG_NAME = "From_Native";
private int count = 1;
private Handler handler;
private final Runnable runnable = new Runnable() {
@Override
public void run() {
int TOTAL_COUNT = 100;
if (count > TOTAL_COUNT) {
attachEvent.endOfStream();
} else {
double percentage = ((double) count / TOTAL_COUNT);
Log.w(TAG_NAME, "\nParsing From Native: " + percentage);
attachEvent.success(percentage);
}
count++;
handler.postDelayed(this, 200);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new EventChannel(Objects.requireNonNull(getFlutterEngine()).getDartExecutor(), STREAM).setStreamHandler(
new EventChannel.StreamHandler() {
@Override
public void onListen(Object args, final EventChannel.EventSink events) {
Log.w(TAG_NAME, "Adding listener");
attachEvent = events;
count = 1;
handler = new Handler();
runnable.run();
}
@Override
public void onCancel(Object args) {
Log.w(TAG_NAME, "Cancelling listener");
handler.removeCallbacks(runnable);
handler = null;
count = 1;
attachEvent = null;
System.out.println("StreamHandler - onCanceled: ");
}
}
);
}
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacks(runnable);
handler = null;
attachEvent = null;
}
}
完整代码 (Flutter)
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static const stream = EventChannel('com.chamelalaboratory.demo.flutter_event_channel/eventChannel');
late StreamSubscription _streamSubscription;
double _currentValue = 0.0;
void _startListener() {
_streamSubscription = stream.receiveBroadcastStream().listen(_listenStream);
}
void _cancelListener() {
_streamSubscription.cancel();
setState(() {
_currentValue = 0;
});
}
void _listenStream(value) {
debugPrint("Received From Native: $value\n");
setState(() {
_currentValue = value;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
//Progress bar
Padding(
padding: const EdgeInsets.all(8.0),
child: LinearProgressIndicator(
value: _currentValue,
backgroundColor: Colors.blue.shade50,
),
),
const SizedBox(
height: 5,
),
// Value in text
Text("Received Stream From Native: $_currentValue".toUpperCase(),
textAlign: TextAlign.justify),
const SizedBox(
height: 50,
),
//Start Btn
TextButton(
onPressed: () => _startListener(),
child: Text("Start Counter".toUpperCase()),
),
const SizedBox(
height: 50,
),
//Cancel Btn
TextButton(
onPressed: () => _cancelListener(),
child: Text("Cancel Counter".toUpperCase()),
),
],
),
),
);
}
}