Flutter-BLoC第三講

本篇已同步到 個(gè)人博客 冯丙,歡迎常來(lái)船老。

本文為《Flutter Bloc Package》的譯文酥筝,原文地址滚躯,若轉(zhuǎn)載譯文請(qǐng)注明出處。

image.png

在使用Flutter工作一段時(shí)間之后嘿歌,我決定創(chuàng)建一個(gè)軟件包以幫助我經(jīng)常使用的東西:BLoC模式掸掏。
對(duì)于那些不熟悉BLoC模式的人來(lái)說(shuō),它是一種設(shè)計(jì)模式宙帝,有助于將表示層與業(yè)務(wù)邏輯分開丧凤。你在這里了解更多。

使用BLoC模式可能具有挑戰(zhàn)性,因?yàn)樾枰?duì)Streams和Reactive Programming的理解步脓。但它的核心是BLoC非常簡(jiǎn)單:

BLoC 將event流作為輸入愿待,并將它們轉(zhuǎn)換為state流作為輸出。

image.png

我們現(xiàn)在可以在bloc的dart包的幫助下使用這種強(qiáng)大的設(shè)計(jì)模式靴患。

該軟件包抽象了模式的反應(yīng)方面仍侥,允許開發(fā)人員專注于將事件(event)轉(zhuǎn)換為狀態(tài)(state)。

讓我們從定義這些術(shù)語(yǔ)開始......

詞匯表

Events 是Bloc的輸入鸳君。它們通常是UI事件农渊,例如按鈕按下。Events被分發(fā)(dispatched)并且被轉(zhuǎn)換為States或颊。

States 是Bloc的輸出砸紊。表示組件可以監(jiān)聽狀態(tài)流 并根據(jù)給定狀態(tài)重繪其自身的部分(BlocBuilder有關(guān)詳細(xì)信息,請(qǐng)參閱參考資料)囱挑。

Transitions 發(fā)生在 調(diào)用mapEventToState之后 但在更新了bloc的state之前 調(diào)度了一個(gè)Event

現(xiàn)在我們了解事件和狀態(tài)醉顽,我們可以看一下Bloc API。

BLOC API

mapEventToState

當(dāng)一個(gè)類繼承Bloc時(shí)看铆,必須實(shí)現(xiàn) mapEventToState 方法徽鼎, 該函數(shù)將傳入事件作為參數(shù)。
只要UI層觸發(fā)一個(gè)事件弹惦,就會(huì)調(diào)用 mapEventToState否淤。
mapEventToState 必須將該event轉(zhuǎn)換為新state,并以UI層使用的Stream形式返回新狀態(tài)棠隐。

dispatch

dispatch 是一個(gè) 接受 event 并觸發(fā) mapEventToState 的方法石抡。
可以從表示層調(diào)用dispatch 或 從Bloc內(nèi)部(見例子)并通知Bloc一個(gè)新 event。

initialState

initialState是處理任何事件之前的狀態(tài)(在mapEventToState被調(diào)用之前)助泽。
如果未實(shí)現(xiàn)啰扛,則為initialState null嚎京。

transform

transform是一個(gè) 在調(diào)用mapEventToState之前 可以重寫以轉(zhuǎn)換 Stream<Event> .
這允許使用distinct() 和 debounce() 的操作。

onTransition

onTransition 是一個(gè) 每次 transform 發(fā)生時(shí)都可以重寫以進(jìn)行處理 的方法隐解。
調(diào)度新event 并調(diào)用mapEventToState時(shí)發(fā)生transition鞍帝。
onTransition 在更新 bloc 狀態(tài)之前 被調(diào)用。
這是添加特定于塊的日志記錄/分析的好地方

讓我們創(chuàng)建一個(gè)counter bloc煞茫!

enum CounterEvent { increment, decrement }

class CounterBloc extends Bloc<CounterEvent, int> {
  @override
  int get initialState => 0;

  @override
  Stream<int> mapEventToState(CounterEvent event) async* {
    switch (event) {
      case CounterEvent.decrement:
        yield currentState - 1;
        break;
      case CounterEvent.increment:
        yield currentState + 1;
        break;
    }
  }
}

創(chuàng)建一個(gè)BLoC 需要作如下操作:

  • 定義所有 event 和 state
  • 繼承Bloc
  • 重寫 initialState 和 mapEventToState

在這種情況下帕涌,我們的 events 是CounterEvents ,states 是 integers

CounterBloc 轉(zhuǎn)換 CounterEvents 為 integers。

我們可以通過(guò) dispatch 來(lái) 通知CounterBloc 事件

void main() {
  final counterBloc = CounterBloc();

  counterBloc.dispatch(CounterEvent.increment);
  counterBloc.dispatch(CounterEvent.decrement);
}

為了觀察狀state 的 轉(zhuǎn)換(Transitions)续徽,我們可以重寫onTransition蚓曼。

enum CounterEvent { increment, decrement }

class CounterBloc extends Bloc<CounterEvent, int> {
  @override
  int get initialState => 0;
  
  @override
  void onTransition(Transition<CounterEvent, int> transition) {
    print(transition);
  }

  @override
  Stream<int> mapEventToState(CounterEvent event) async* {
    switch (event) {
      case CounterEvent.decrement:
        yield currentState - 1;
        break;
      case CounterEvent.increment:
        yield currentState + 1;
        break;
    }
  }
}

現(xiàn)在,每當(dāng)發(fā)出(dispatch)一個(gè)CounterEvent我們的Bloc將響應(yīng)一個(gè)新的integer狀態(tài)钦扭,我們將看到一個(gè)transition被輸出到控制臺(tái)纫版。

現(xiàn)在讓我們使用Flutter構(gòu)建一個(gè)UI,并使用flutter_bloc 包將UI連接到我們的CounterBloc客情。

BlocBuilder

BlocBuilder是一個(gè)Flutter小部件其弊,它需要一個(gè)Bloc和一個(gè)構(gòu)建器函數(shù)。
BlocBuilder處理構(gòu)建窗口小部件以響應(yīng)新state裹匙。
BlocBuilder與StreamBuilder非常相似瑞凑,但它有一個(gè)更簡(jiǎn)單的API來(lái)減少所需的樣板代碼量末秃。

BlocProvider

BlocProvider是一個(gè)Flutter小部件概页,它通過(guò) BlocProvider.of(context)為其子女提供了一個(gè)bloc。
它用作依賴注入(DI)小部件, 這樣一個(gè)bloc實(shí)例 可以被提供給子樹中的多個(gè)小部件练慕。

現(xiàn)在讓我們構(gòu)建 counter App

class App extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _AppState();
}

class _AppState extends State<App> {
  final CounterBloc _counterBloc = CounterBloc();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: BlocProvider<CounterBloc>(
        bloc: _counterBloc,
        child: CounterPage(),
      ),
    );
  }

  @override
  void dispose() {
    _counterBloc.dispose();
    super.dispose();
  }
}

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final CounterBloc _counterBloc = BlocProvider.of<CounterBloc>(context);

    return Scaffold(
      appBar: AppBar(title: Text('Counter')),
      body: BlocBuilder<CounterEvent, int>(
        bloc: _counterBloc,
        builder: (BuildContext context, int count) {
          return Center(
            child: Text(
              '$count',
              style: TextStyle(fontSize: 24.0),
            ),
          );
        },
      ),
      floatingActionButton: Column(
        crossAxisAlignment: CrossAxisAlignment.end,
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          Padding(
            padding: EdgeInsets.symmetric(vertical: 5.0),
            child: FloatingActionButton(
              child: Icon(Icons.add),
              onPressed: () {
                _counterBloc.dispatch(CounterEvent.increment);
              },
            ),
          ),
          Padding(
            padding: EdgeInsets.symmetric(vertical: 5.0),
            child: FloatingActionButton(
              child: Icon(Icons.remove),
              onPressed: () {
                _counterBloc.dispatch(CounterEvent.decrement);
              },
            ),
          ),
        ],
      ),
    );
  }
}

該App小部件是StatefulWidget惰匙,負(fù)責(zé)創(chuàng)建和銷毀 CounterBloc。
它讓 CounterBloc 使用 BlocProvider 小部件可用于 CounterPage 小部件铃将。

CounterPage小部件是StatelessWidget项鬼, 它使用BlocBuilder重建UI以響應(yīng)CounterBloc的狀態(tài)變化。

此時(shí)劲阎,我們已經(jīng)成功地將我們的表示層與業(yè)務(wù)邏輯層分開绘盟。請(qǐng)注意,CounterPage窗口小部件對(duì)用戶點(diǎn)擊按鈕時(shí)發(fā)生的情況一無(wú)所知悯仙。小部件只是告訴CounterBloc用戶按下了遞增或遞減按鈕龄毡。

有關(guān)更多示例和詳細(xì)文檔,請(qǐng)查看官方集團(tuán)文檔锡垄。

相關(guān)鏈接:

bloc dart包
flutter_bloc包
flutter_bloc使用官方文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末沦零,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子货岭,更是在濱河造成了極大的恐慌路操,老刑警劉巖疾渴,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異屯仗,居然都是意外死亡搞坝,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門魁袜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)瞄沙,“玉大人,你說(shuō)我怎么就攤上這事慌核【嗑常” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵垮卓,是天一觀的道長(zhǎng)垫桂。 經(jīng)常有香客問(wèn)我,道長(zhǎng)粟按,這世上最難降的妖魔是什么诬滩? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮灭将,結(jié)果婚禮上疼鸟,老公的妹妹穿的比我還像新娘。我一直安慰自己庙曙,他們只是感情好空镜,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著捌朴,像睡著了一般吴攒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上砂蔽,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天洼怔,我揣著相機(jī)與錄音,去河邊找鬼左驾。 笑死镣隶,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的诡右。 我是一名探鬼主播安岂,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼稻爬!你這毒婦竟也來(lái)了嗜闻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤桅锄,失蹤者是張志新(化名)和其女友劉穎琉雳,沒(méi)想到半個(gè)月后样眠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡翠肘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年檐束,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片束倍。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡被丧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绪妹,到底是詐尸還是另有隱情甥桂,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布邮旷,位于F島的核電站黄选,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏婶肩。R本人自食惡果不足惜办陷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望律歼。 院中可真熱鬧民镜,春花似錦、人聲如沸险毁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)辱揭。三九已至离唐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間问窃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工完沪, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留域庇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓覆积,卻偏偏與公主長(zhǎng)得像听皿,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子宽档,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容