Flutter 实例 - 从本地到Flutter通信 - Event Channels

11,603 阅读4分钟

Dart4Flutter - 01 – 变量、类型和函数

Dart4Flutter – 02 –控制流 和异常

Dart4Flutter – 03 – 类和泛型

Dart4Flutter – 04 – 异步和库

Dart4Flutter - 拾遗01 - flutter-dart环境搭建

Dart4Flutter - 不可变性

Flutter入门 - 状态管理

Flutter 入门实例1

Flutter 入门 - Container 属性详解

Flutter 入门-本地访问-MethodChannel

Flutter 实例 - 加载更多的ListView

Flutter 实例 - 从本地到Flutter通信 - Event Channels

Flutter是google推出的用于移动应用开发的SDK。更多详细信息参考官网。

Flutter应用任然需要和本地的代码java或者Swift通信。你任然需要本地代码获取移动设备硬件或者进行计算密集型操作。这个和React-Native的设计是一样的,但是他们实现有很大的差别。

我们不讨论两个SDK谁比较厉害。我们只是研究一下,关于从本地代码到Flutter通信的问题。

Flutter的官方的文档写的非常好。在platform channels章节,使用大量的例子详细说明了,通过MethodChannel和本地通信。 但是文档只是描述从Flutter到本地的通信,但是没有从本地到Flutter的通信。

需要本地代码的场景

实现和使用MethodChannel接口和RPC很像。从Flutter调用一个本地的方法,本地方法执行,最终以一个错误或者信息为响应。这种方法调用可以获取当前电池的状态、网络状态信息或者温度数据。一旦本地方法做出相应,就不会再发送任何的信息,直到下次方法调用。

我对从本地到Flutter发送数据比较感兴趣。这可能包括持续更新BLE或WiFi扫描结果,加速度计和陀螺仪,甚至是密集数据收集的定期状态更新。

在搜索完java Api文档之后,发现了EventChannel.StreamHandler可以解决上面的问题。Dart语言也是支持Stream,他来自Akka/Monix/Rx,而且比较受欢迎的特性。

本地发送信息

添加一个针对数据流的platform channel很简单。你需要简单的实现StreamHandler接口,然后发射你的事件。

public class MainActivity extends FlutterActivity {
    public static final String STREAM = "com.yourcompany.eventchannelsample/stream"; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        new EventChannel(getFlutterView(), STREAM).setStreamHandler(
                new EventChannel.StreamHandler() {
                    @Override
                    public void onListen(Object args, final EventChannel.EventSink events) {
                        Log.w(TAG, "adding listener");
                    }

                    @Override
                    public void onCancel(Object args) {
                        Log.w(TAG, "cancelling listener");
                    }
                }
        );
    }
}

为了保证例子大多数手机可以运行,我们选用RxJava库,将时间间隔作为事件发送出来。注意你可以将任何的信息发送到Flutter应用。

public void onListen(Object args, EventChannel.EventSink events) {
    Log.w(TAG, "adding listener");
    timerSubscription = Observable
            .interval(0, 1, TimeUnit.SECONDS)
            .subscribe(
                    (Long timer) -> {
                        Log.w(TAG, "emitting timer event " + timer);
                        events.success(timer);// 发送事件
                    },
                    (Throwable error) -> {
                        Log.e(TAG, "error in emitting timer", error);
                        events.error("STREAM", "Error in processing observable", error.getMessage());
                    },
                    () -> Log.w(TAG, "closing the timer observable")
            );
}

@Override
public void onCancel(Object args) {
    Log.w(TAG, "cancelling listener");
    if (timerSubscription != null) {
        timerSubscription.dispose();
        timerSubscription = null;
    }
}

Dart 接受信息

Dart内置支持Stream,EventChannel使用Stream的功能通知何时本地代码开始发送事件和停止发送事件。为了从本地开始发送事件,只需要给platform channel流添加监听器。

static const stream =
    const EventChannel('com.yourcompany.eventchannelsample/stream');

StreamSubscription _timerSubscription = null;

void _enableTimer() {
  if (_timerSubscription == null) {
    _timerSubscription = stream.receiveBroadcastStream().listen(_updateTimer); // 添加监听
  }
}

void _disableTimer() {
  if (_timerSubscription != null) {
    _timerSubscription.cancel();
    _timerSubscription = null;
  }
}

为了显示从本地来的更新次数,_updateTimer()方法这是修改_timer状态

void _updateTimer(timer) {
  debugPrint("Timer $timer");
  setState(() => _timer = timer);
}

下面的log展示了,添加监听,事件发送,事件接受,以及取消channel。

W/eventchannelsample(32641): adding listener
W/eventchannelsample(32641): emitting timer event 0
I/flutter (32641): Timer 0
W/eventchannelsample(32641): emitting timer event 1
I/flutter (32641): Timer 1
W/eventchannelsample(32641): emitting timer event 2
I/flutter (32641): Timer 2
W/eventchannelsample(32641): emitting timer event 3
I/flutter (32641): Timer 3
W/eventchannelsample(32641): emitting timer event 4
I/flutter (32641): Timer 4
W/eventchannelsample(32641): emitting timer event 5
I/flutter (32641): Timer 5
W/eventchannelsample(32641): cancelling listener
W/eventchannelsample(32641): adding listener
W/eventchannelsample(32641): emitting timer event 0
I/flutter (32641): Timer 0
W/eventchannelsample(32641): emitting timer event 1
I/flutter (32641): Timer 1

总结

首先回顾了从Flutter到本地的通信方式,而且官方文档也有详细讲解。在发现从本地到Flutter通信的问题时,我们发现了EventChannel,通过发送和接受事件,完成成了本地到Flutter的通信。

参考