Flutter中消息傳遞

首發於個人公衆號javascript

Flutter中消息傳遞java

前言

在native開發中消息傳遞有多種手段,系統的廣播,第三方的eventbus等,在flutter中會有哪些手段呢?本篇將會介紹git

Flutter中的消息傳遞

InheritedWidget

InheritedWidget是Flutter中很是重要的一個功能型Widget,它能夠高效的將數據在Widget樹中向下傳遞、共享,這在一些須要在Widget樹中共享數據的場景中很是方便, 咱們常常經過這樣的方式,經過BuildContext,能夠拿到ThemeMediaQuerygithub

InheritedWidget和React中的context功能相似,和逐級傳遞數據相比,它們能實現組件跨級傳遞數據。InheritedWidget的在Widget樹中數據傳遞方向是從上到下的,這和Notification的傳遞方向正好相反。app

在介紹StatefulWidget時,咱們提到State對象有一個回調didChangeDependencies,它會在「依賴」發生變化時被Flutter Framework調用。而這個「依賴」指的就是是否使用了父widget中InheritedWidget的數據,若是使用了,則表明有依賴,若是沒有使用則表明沒有依賴。這種機制可使子組件在所依賴的主題、locale等發生變化時有機會來作一些事情 好比less

//獲得狀態欄的高度
var statusBarHeight = MediaQuery.of(context).padding.top;
//複製合併出新的主題
var copyTheme =Theme.of(context).copyWith(primaryColor: Colors.blue);
複製代碼

使用InheritedWidget

主要涉及2部分工做量ide

  • 建立一個繼承自 InheritedWidget 的類,使用時將其插入 Widget 樹
  • 經過 BuildContext 對象提供的 inheritFromWidgetOfExactType 方法查找 Widget 樹中最近的一個特定類型的 InheritedWidget 類的實例

共享數據類學習

class InheritedContext extends InheritedWidget {

  //數據
  final InheritedTestModel inheritedTestModel;

  //點擊+號的方法
  final Function() increment;

  //點擊-號的方法
  final Function() reduce;

  InheritedContext({
    Key key,
    @required this.inheritedTestModel,
    @required this.increment,
    @required this.reduce,
    @required Widget child,
  }) : super(key: key, child: child);

  static InheritedContext of(BuildContext context) {
    return context.inheritFromWidgetOfExactType(InheritedContext);
  }

  //是否重建widget就取決於數據是否相同
  @override
  bool updateShouldNotify(InheritedContext oldWidget) {
    return inheritedTestModel != oldWidget.inheritedTestModel;
  }
}
複製代碼

在widget中使用共享數據ui

class CustomerWidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final inheritedContext = InheritedContext.of(context);

    final inheritedTestModel = inheritedContext.inheritedTestModel;

    return new Padding(
      padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
      child: new Text(
        '當前count:${inheritedTestModel.count}',
        style: new TextStyle(fontSize: 20.0),
      ),
    );
  }
}
複製代碼

在樹中從上向下傳遞this

@override
Widget build(BuildContext context) {
  return new InheritedContext(
      inheritedTestModel: inheritedTestModel,
      increment: _incrementCount,
      reduce: _reduceCount,
      child: new Scaffold(
        appBar: new AppBar(
          title: new Text('InheritedWidgetTest'),
        ),
        body: new Column(
          children: <Widget>[
            new Padding(
              padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
              child: new Text('咱們常使用的\nTheme.of(context).textTheme\nMediaQuery.of(context).size等\n就是經過InheritedWidget實現的',
                style: new TextStyle(fontSize: 20.0),),
            ),
            new CustomerWidgetA(),
            new CustomerWidgetB(),
            new CustomerWidgetC(),
          ],
        ),
      ));
}
複製代碼

具體代碼能夠查看

常見錯誤

MediaQuery.of() called with a context that does not contain a MediaQuery

見ss stackoverflow.com/questions/5… You need a MaterialApp or a WidgetsApp arround your widget. They provide the MediaQuery. When you call .of(context)

Notification

notification 跟inheritedWidget偏偏相反,是從 子節點向父節點發送消息在Widget樹中,每個節點均可以分發通知,通知會沿着當前節點(context)向上傳遞,全部父節點均可以經過NotificationListener來監聽通知,Flutter中稱這種通知由子向父的傳遞爲「通知冒泡」(Notification Bubbling)。Flutter中不少地方使用了通知,如可滾動(Scrollable) Widget中滑動時就會分發ScrollNotification,而Scrollbar正是經過監聽ScrollNotification來肯定滾動條位置的。

使用Notification

  • 自定義通知 要繼承自Notification類
  • 分發通知 Notification有一個dispatch(context)方法,它是用於分發通知的,咱們說過context實際上就是操做Element的一個接口,它與Element樹上的節點是對應的,通知會從context對應的Element節點向上冒泡。
class CustomerNotification extends Notification {
  CustomerNotification(this.msg);
  final String msg;
}
複製代碼
class NotificationStudyState extends State<NotificationStudy> {
  String _msg = "";

  @override
  Widget build(BuildContext context) {
    //監聽通知
    return NotificationListener<CustomerNotification>(
      onNotification: (notification) {
        setState(() {
          _msg += notification.msg + " ";
        });
      },
      child: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
// RaisedButton(
// onPressed: () => CustomerNotification("Hello NotificationStudy").dispatch(context),
// child: Text("Send Notification"),
// ),
            Builder(
              builder: (context) {
                return RaisedButton(
                  //按鈕點擊時分發通知
                  onPressed: () => CustomerNotification("Hello NotificationStudy").dispatch(context),
                  child: Text("Send Notification"),
                );
              },
            ),
            Text(_msg)
          ],
        ),
      ),
    );
  }
}
複製代碼

注意:代碼中註釋的部分是不能正常工做的,由於這個context是根Context,而NotificationListener是監聽的子樹,因此咱們經過Builder來構建RaisedButton,來得到按鈕位置的context。

以上代碼 參見 github.com/xsfelvis/le…

事件總線

目前在已經有了一個eventbus插件

pub.flutter-io.cn/packages/ev…

用法跟原生eventbus相似

  • 引入
import 'package:event_bus/event_bus.dart';

EventBus eventBus = new EventBus();
複製代碼
  • 監聽事件
eventBus.on().listen((event) { 
    print(event.runtimeType);
});
複製代碼
  • 發送事件
eventBus.fire(event);
複製代碼
歡迎關注個人公衆號,一塊兒學習,共同提升~
複製代碼

公衆號小.jpg
相關文章
相關標籤/搜索