Flutter 例項 - 從本地到Flutter通訊 - Event Channels

黃馬發表於2018-07-03

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 例項 - 從本地到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);
}
複製程式碼

Flutter 例項 - 從本地到Flutter通訊 - Event Channels

下面的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的通訊。

參考

相關文章