Flutter BLoC 教程:使用 BLoC 模式進(jìn)行狀態(tài)管理
什么是區(qū)塊鏈?
BLoC代表業(yè)務(wù)邏輯組件;它旨在將應(yīng)用程序的業(yè)務(wù)邏輯與用戶界面分開,使應(yīng)用程序代碼更加明確、可擴(kuò)展和可測試。
開發(fā)者:費(fèi)利克斯·安格洛夫
贊助商:Very Good Ventures、Stream、Miquido
版本:flutter_bloc: ^8.0.1(寫文章時(shí))
BLoC 設(shè)計(jì)模式的優(yōu)缺點(diǎn)
在繼續(xù)學(xué)習(xí)flutter bloc 教程之前,讓我們檢查一下 bloc 設(shè)計(jì)模式的一些優(yōu)缺點(diǎn)。
使用 BLoC 的優(yōu)點(diǎn)
關(guān)于不同場景的優(yōu)秀文檔。
將業(yè)務(wù)邏輯與 UI 分離,從而使代碼易于理解。
使產(chǎn)品更具可測試性。
易于跟蹤應(yīng)用程序經(jīng)歷的狀態(tài)。
使用 BLoC 的缺點(diǎn)
學(xué)習(xí)曲線有點(diǎn)陡峭。
不推薦用于簡單應(yīng)用
更多樣板代碼,但可以通過擴(kuò)展來處理。
Flutter BLoC 教程目標(biāo)
我們將構(gòu)建一個(gè)相對簡單的應(yīng)用程序來演示 BLoC 如何使用流來管理狀態(tài)并為 bloc 編寫一些測試。
我們將構(gòu)建一個(gè)文本更改應(yīng)用程序;按文本將更改并顯示每個(gè)按鈕。您可以參考下面的 GIF。
初始設(shè)置
1.確保安裝集團(tuán)在你的編輯器中擴(kuò)展;它將幫助創(chuàng)建項(xiàng)目所需的所有樣板代碼和文件(右鍵單擊 lib 文件夾,它將為您提供為項(xiàng)目生成 bloc 的選項(xiàng))。
2. 確保將你的 pubspec.yaml 文件與我的相匹配,以避免出現(xiàn)任何問題。
想要輕松無憂地開發(fā) Flutter 應(yīng)用程序嗎?
Bacancy 在這里等你!聯(lián)系我們聘請 Flutter 開發(fā)人員,以出色的問題解決能力高效地滿足您的項(xiàng)目要求。
了解 BLoC 概念:事件和狀態(tài)
讓游戲開始吧。
要了解 bloc 的工作原理,我們需要知道什么是事件和狀態(tài)。
事件:事件是應(yīng)用程序的輸入(例如 button_press 以加載圖像、文本輸入或我們的應(yīng)用程序可能希望接收的任何其他用戶輸入)。
狀態(tài):狀態(tài)只是應(yīng)用程序的狀態(tài),可以根據(jù)接收到的事件進(jìn)行更改。
Bloc 管理這些事件和狀態(tài),即它接收事件流并將它們轉(zhuǎn)換為狀態(tài)流作為輸出。
創(chuàng)建事件
@immutable抽象類 AppBlocEvent {
常量 AppBlocEvent();}
@immutable類 ChangeTextEvent 擴(kuò)展 AppBlocEvent {
常量 ChangeTextEvent();}
在flutter bloc 教程中繼續(xù)前進(jìn)。在這里,我們創(chuàng)建了一個(gè)ChangeTextEvent,它會在單擊按鈕時(shí)觸發(fā)。
我們有一個(gè)抽象的AppBlocEvent類,因?yàn)?Bloc 期望將單個(gè)事件添加到流中。盡管如此,由于一個(gè)應(yīng)用程序中可以有多個(gè)事件,我們創(chuàng)建了一個(gè)抽象類并在我們想要?jiǎng)?chuàng)建任何新事件來處理多個(gè)事件并將其傳遞給 bloc 時(shí)擴(kuò)展它。
創(chuàng)建狀態(tài)
@immutableAppState 類擴(kuò)展 Equatable {
最終整數(shù)索引;
最終字符串文本;
常量 AppState.empty()
: 指數(shù) = 0,
text = '初始文本';
常量 AppState({
需要this.index,
需要this.text,
});
@覆蓋
List<Object> get props => [index, text];}
同樣,我們可以在此應(yīng)用程序中創(chuàng)建不同的狀態(tài)。我們沒有很多州。因此,我們創(chuàng)建了一個(gè)單一的狀態(tài)來管理應(yīng)用程序;然而,我們可以通過創(chuàng)建一個(gè)抽象的 appstate 并將其擴(kuò)展到我們的自定義狀態(tài)來創(chuàng)建類似于事件的多個(gè)狀態(tài)。
AppState.empty只是應(yīng)用程序最初加載的初始狀態(tài)。
Equatable (get props)這里是用來和狀態(tài)進(jìn)行比較的。如果它們相等,它將用于測試區(qū)塊。
使用 BLoC 模式的事件和狀態(tài)管理
AppBlocBloc 類擴(kuò)展了 Bloc{
最終名單文本列表 = [
'初始文本',
'更改文本',
'再次改變',
];
AppBlocBloc() : super(const AppState.empty()) {
在((事件,發(fā)出){
嘗試 {
int newIndex = state.index + 1;
如果(新索引 >= textList.length){
新指數(shù) = 0;
}
發(fā)射(
應(yīng)用程序狀態(tài)(
指數(shù):新指數(shù),
文本:textList[newIndex],
),
);
} on Exception catch (e) {
// 忽略:avoid_print
打?。╡);
}
});
}}
說明
這是包含我們應(yīng)用程序業(yè)務(wù)邏輯的部分。
在
當(dāng)通過單擊按鈕將 ChangeTextEvent 添加到流時(shí)執(zhí)行,它接收事件,即您想要與觸發(fā)事件一起傳遞的任何信息,您可以使用它訪問它(如 event.any_info - 你必須更改你的事件相應(yīng)地分類),emit 用于為該特定事件發(fā)出狀態(tài)。 state.index 允許您訪問應(yīng)用程序的當(dāng)前狀態(tài)。
emit(AppState(…)): emit(…) 用于輸出新狀態(tài)并導(dǎo)致 build() 函數(shù)的重建。
把碎片放在一起。
到目前為止,事件、狀態(tài)、集團(tuán)和我們的應(yīng)用程序的 UI 沒有以任何方式連接。讓我們開始將它們拼湊起來。
提供我們的 BLoC
導(dǎo)入“包:flutter/material.dart”;導(dǎo)入“包:flutter_bloc/flutter_bloc.dart”;導(dǎo)入“包:text_change/text_controller.dart”;導(dǎo)入“bloc/app_bloc_bloc.dart”;導(dǎo)入“bloc/app_bloc_state.dart”;類 App 擴(kuò)展 StatelessWidget {
const App({Key?key}) : super(key: key);
@覆蓋
小部件構(gòu)建(BuildContext 上下文){
返回 MaterialApp(
標(biāo)題:'顫振演示',
主題:主題數(shù)據(jù)(
primarySwatch: Colors.blue,
),
家:BlocProvider(
創(chuàng)建:(上下文)=> AppBlocBloc(),
孩子:腳手架(
應(yīng)用欄:應(yīng)用欄(
title: const Text('文本變化'),
),
正文:BlocConsumer(
偵聽器:(上下文,狀態(tài)){},
建設(shè)者:(上下文,狀態(tài)){
返回文本控制器(
文本:state.text,
);
},
),
),
),
);
}}
說明:App.dart
BlocProvider(...):我們使用它來提供我們的 bloc 實(shí)例,方法是將它放置在應(yīng)用程序的根目錄下方,以便在整個(gè)應(yīng)用程序中都可以訪問它。
創(chuàng)建:它創(chuàng)建我們的 AppBloBloc 的實(shí)例。
BlocConsumer(...):這是一切發(fā)生的地方。
它有一個(gè)名為 listener 的屬性,它監(jiān)聽狀態(tài)變化,并且可以隨著狀態(tài)變化以特定方式對特定狀態(tài)做出反應(yīng)。
builder:它負(fù)責(zé)構(gòu)建 UI 并在每次狀態(tài)更改時(shí)重新構(gòu)建。blocConsumer 還包含 listenWhen 和 buildWhen,正如名稱所述,可以對其進(jìn)行定制以對指定狀態(tài)做出反應(yīng)。
觸發(fā)事件和狀態(tài)
類 TextChangeController 擴(kuò)展 StatelessWidget {最終字符串文本;const TextChangeController({Key? key, required this.text}) : super(key: key);@覆蓋小部件構(gòu)建(BuildContext 上下文){
返回列
孩子們:[
文本變化(
文字:文字,
), // 文本變化
高架按鈕(
onPressed: () =>
上下文.read().add(const ChangeTextEvent()),
child: const Text('更改文本'),
), // 高架按鈕
), //[ ]
); // 柱子
))
在這里,我們將ChangetTextEvent添加到事件流中,從而觸發(fā)狀態(tài)更改,從而導(dǎo)致 BlocConsumer 中的 builder() 重建,并將更改的文本顯示在屏幕上。
你有它?。∈褂梅蛛x的 UI 和業(yè)務(wù)邏輯,您可以更改 UI 代碼,只需插入 Bloc。它的工作原理是一樣的。
測試 BLoC 設(shè)計(jì)模式
為了測試 bloc,您需要兩個(gè)包:
bloc_test
顫動測試
只需在測試文件夾中,創(chuàng)建 app_bloc_test.dart 文件并開始編寫測試。
在內(nèi)部我們將測試兩個(gè)條件:
應(yīng)用程序的初始狀態(tài),即 AppState.empty()。
按下按鈕時(shí)狀態(tài)會發(fā)生變化。
給你!????
無效主要(){
塊測試(
'初始狀態(tài)',
構(gòu)建:()=> AppBlocBloc(),
驗(yàn)證:(appState)=>
expect(appState.state, const AppState.empty(), reason: 'Initial State'),
);
塊測試(
'添加 MyEvent 時(shí)發(fā)出 [MyState]。',
構(gòu)建:()=> AppBlocBloc(),
行為:(bloc) => bloc.add(const ChangeTextEvent()),
期望:()=>常量[
應(yīng)用程序狀態(tài)(
指數(shù):1,
文本:'更改文本',
),
],
);}
解釋
blocTest 來自 bloc_test 包。
build():它返回 AppBlocBloc() 的一個(gè)實(shí)例。
verify 和 expect 顧名思義它們匹配狀態(tài) expect(actual, matcher, reason)。
act:將事件添加到事件流中。
Github 存儲庫:Flutter BLoC 簡單示例
隨意克隆存儲庫:flutter-bloc-demo并開始試驗(yàn)代碼。
結(jié)論
Flutter BLoC 教程有助于您開始使用 BLoC 模式進(jìn)行狀態(tài)管理。我們將帶著另一個(gè) Flutter 教程回來;到那時(shí),請?jiān)L問Flutter 教程頁面并了解有關(guān) Flutter 概念的更多信息。讓我們知道您是否希望涵蓋任何特定主題。給我們回信您的建議和反饋??鞓肪幋a!