Flutter響應(yīng)式編程 - Stream

在Dart庫(kù)中祭隔,有兩種實(shí)現(xiàn)異步編程的方式(Future和Stream)货岭,使用它們只需要在代碼中引入dart:async即可。

Flutter 中疾渴,整個(gè) Stream 主要包含了 StreamController千贯、Sink 、Stream 搞坝、StreamSubscription 四個(gè)對(duì)象搔谴,通過(guò)這四個(gè)對(duì)象來(lái)操控整個(gè)Stream的運(yùn)行。

  • StreamController

有一個(gè)事件源叫 Stream桩撮,為了方便控制 Stream 敦第,官方提供了使用 StreamController 作為管理;同時(shí)它對(duì)外提供了 StreamSink 對(duì)象作為事件輸入口店量,可通過(guò) sink 屬性訪問(wèn); 又提供 stream 屬性提供 Stream 對(duì)象的監(jiān)聽和變換芜果,最后得到的 StreamSubscription 可以管理事件的訂閱。

可以說(shuō)融师, StreamController就是如其名字所示一樣用來(lái)管理其他三個(gè)對(duì)象的對(duì)象右钾。

  • StreamSink

sink英文的意思為水槽,我們可以將其理解為日常生活中的廚房的洗碗槽诬滩,洗碗槽(sink)中的水(data)會(huì)流進(jìn)管子(stream)中霹粥。一般作為事件的入口,提供如 add 疼鸟, addStream 等后控。

  • StreamSubscription

這是一個(gè)事件訂閱后的對(duì)象,空镜,Stream中有兩種訂閱模式浩淘,分別是單點(diǎn)訂閱和廣播捌朴。

表面上用于管理訂閱過(guò)等各類操作,如 cacenl 张抄、pause 砂蔽,同時(shí)在內(nèi)部也是事件的中轉(zhuǎn)關(guān)鍵。

  • Stream

事件源本身署惯,一般可用于監(jiān)聽事件或者對(duì)事件進(jìn)行轉(zhuǎn)換左驾,如 listen 、 where 极谊。

什么是Stream诡右?

為了將Stream的概念可視化與簡(jiǎn)單化,可以將它想成是管道(pipe)的兩端轻猖,它只允許從一端插入數(shù)據(jù)并通過(guò)管道從另外一端流出數(shù)據(jù)帆吻。
在Flutter中,

  • 我們將這樣的管道稱作Stream咙边;
  • 為了控制Stream猜煮,我們通常可以使用StreamController來(lái)進(jìn)行管理败许;
  • 為了向Stream中插入數(shù)據(jù)王带,StreamController提供了類型為StreamSink的屬性sink作為入口;
  • StreamController提供stream屬性作為數(shù)據(jù)的出口檐束。

class StreamDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('StreamDemo'),
        elevation: 0.0,
      ),
      body: StreamTestDemo(),
    );
  }
}

class StreamTestDemo extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return StreamTestDemoState();
  }
}

class StreamTestDemoState extends State<StreamTestDemo> {
  StreamSubscription streamSubscription;
  StreamController<String> _streamDemo;
  StreamSink _sinkDemo;
  var _data = "--";

  @override
  void initState() {
    super.initState();
    //使用StreamController 管理Stream
    _streamDemo = StreamController<String>();
    //為了向Stream中插入數(shù)據(jù)辫秧,StreamController提供了類型為StreamSink的屬性sink作為入口;
    _sinkDemo = _streamDemo.sink;
    //StreamSubscription 可以管理事件的訂閱  取消 暫停  添加
    streamSubscription =
        _streamDemo.stream.listen(onData, onError: onError, onDone: onDone);
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _streamDemo.close();
  }

  void onData(String data) {
    print('---------${data}');
    setState(() {
      _data = data;
    });
  }

  void onError(error) {
    print('--------error:$error');
  }

  void onDone() {
    print('--------Done');
  }

  Future<String> fetchData() async {
    await Future.delayed(new Duration(seconds: 3));
    // throw 'soming err';
    return 'hello word';
  }

  void _addDataToStream() async {
    print('------Add data to stream.');
    String data = await fetchData();
    // _streamDemo.add(data);
    _sinkDemo.add(data);
  }

  void _pauseStream() {
    print('------Pause subscription');
    streamSubscription.pause();
  }

  void _resumeStream() {
    print('------Resume subscription');
    streamSubscription.resume();
  }

  void _cancelStream() {
    print('------Cancel subscription');
    streamSubscription.cancel();
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Container(
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(_data),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                FlatButton(
                  child: Text('Add'),
                  onPressed: _addDataToStream,
                ),
                FlatButton(
                  child: Text('Pause'),
                  onPressed: _pauseStream,
                ),
                FlatButton(
                  child: Text('Resume'),
                  onPressed: _resumeStream,
                ),
                FlatButton(
                  child: Text('Cancel'),
                  onPressed: _cancelStream,
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

如下圖 點(diǎn)擊add 后3s后會(huì)顯示hello word 同時(shí)也可以點(diǎn)擊 暫停 恢復(fù) 取消等 查看結(jié)果


image.png

另外 Stream 還支持多次訂閱
修改代碼

  @override
  void initState() {
    super.initState();
    print('-----Create a stream.');
    //支持多次訂閱
    _streamDemo = StreamController.broadcast();
    _sinkDemo = _streamDemo.sink;
    print('-----Start listening on a stream.');
    _streamDemoSubscription =
        _streamDemo.stream.listen(onData, onError: onError, onDone: onDone);
    _streamDemo.stream.listen(onDataTwo, onError: onError, onDone: onDone);
    print('-----Initialize completed.');
  }


  void onDataTwo(String data) {
    print('-----onDataTwo: $data');
  }

運(yùn)行后便可以查看到兩次的ondata 輸出

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末被丧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子绪妹,更是在濱河造成了極大的恐慌甥桂,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件邮旷,死亡現(xiàn)場(chǎng)離奇詭異黄选,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)婶肩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門办陷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人律歼,你說(shuō)我怎么就攤上這事民镜。” “怎么了险毁?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵制圈,是天一觀的道長(zhǎng)们童。 經(jīng)常有香客問(wèn)我,道長(zhǎng)鲸鹦,這世上最難降的妖魔是什么慧库? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮馋嗜,結(jié)果婚禮上齐板,老公的妹妹穿的比我還像新娘。我一直安慰自己葛菇,他們只是感情好甘磨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著熟呛,像睡著了一般宽档。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上庵朝,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天吗冤,我揣著相機(jī)與錄音,去河邊找鬼九府。 笑死椎瘟,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的侄旬。 我是一名探鬼主播肺蔚,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼儡羔!你這毒婦竟也來(lái)了宣羊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤汰蜘,失蹤者是張志新(化名)和其女友劉穎仇冯,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體族操,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡苛坚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了色难。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泼舱。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖枷莉,靈堂內(nèi)的尸體忽然破棺而出娇昙,到底是詐尸還是另有隱情,我是刑警寧澤依沮,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布涯贞,位于F島的核電站枪狂,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏宋渔。R本人自食惡果不足惜州疾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望皇拣。 院中可真熱鬧严蓖,春花似錦、人聲如沸氧急。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)吩坝。三九已至毒姨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間钉寝,已是汗流浹背弧呐。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嵌纲,地道東北人俘枫。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像逮走,于是被迫代替她去往敵國(guó)和親鸠蚪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355