flutter_bloc使用解析---騷年,你還在手搭bloc嗎!
阿新 • • 發佈:2020-10-22
## 前言
- 首先,有很多的文章在說flutter bloc模式的應用,但是百分之八九十的文章都是在說,使用StreamController+StreamBuilder搭建bloc,提升效能的會加上InheritedWidget,這些文章看了很多,真正寫使用bloc作者開發的flutter_bloc卻少之又少。沒辦法,只能去bloc的github上去找使用方式,最後去bloc官網翻文件。
- 蛋痛,各位叼毛,就不能好好說說flutter_bloc的使用嗎?非要各種抄bloc模式提出作者的那倆篇文章。現在,搞的雜家這個伸手黨要自己去翻文件總結(手動滑稽)。
![表情1](https://cdn.jsdelivr.net/gh/CNAD666/MyData/pic/flutter/blog/20200804152051.png)
**專案效果(建議PC瀏覽器開啟)**
- [Bloc範例效果](http://cnad666.gitee.io/book_web_manage)
- [Cubit範例效果](https://cnad666.gitee.io/flutter_use/#/)
**下面是Flutter_Bloc歷程的一系列連結**
- [Flutter_Bloc起源](https://www.didierboelens.com/2018/08/reactive-programming-streams-bloc/)
- [Flutter_Bloc模式優化](https://www.didierboelens.com/2018/12/reactive-programming-streams-bloc-practical-use-cases/)
- [Flutter_Bloc誕生](https://medium.com/flutter-community/flutter-bloc-package-295b53e95c5c)
- [Flutter_Bloc官網文件](https://bloclibrary.dev/#/)
前面三個,是bloc作者寫的bloc模式文件,典型的觀察者模式的應用,最原始的就是java中CallBack形式。前倆篇文章就是咱們這些大抄子的主要“參考”的資料來源,這三篇文章在掘金上有翻譯版,搜下bloc就能找到。最後一篇文章就是我主要總結歸納的源泉,作者在官網上寫了好幾個demo:計時器,登入,Todos,天氣等等,大家可以自己去看看。
### 問題
初次使用flutter_bloc框架,可能會有幾個疑問
- state裡面定義了太多變數,某個事件只需要更新其中一個變數,其它的變數賦相同值麻煩
- 進入某個模組,進行初始化操作:複雜的邏輯運算,網路請求等,入口在哪定義
## 效果
- 好了,嗶嗶了一堆,看下咱們要用flutter_bloc實現的效果。
![bloc演示](https://cdn.jsdelivr.net/gh/CNAD666/MyData/pic/flutter/blog/20200804152120.gif)
- 直接開Chrome演示,大家在虛擬機器上跑也一樣。
## 引用
- 先說明下,bloc給的api很多,不同的api針對與解決場景不同,我要是把官網那些api全抄過也沒啥意義;不,也有可能可以裝幣,我要是不說明,大家說不定以為是我自己總結的呢!哈哈。
- OK,大家要是想知道全場景的使用,可以去官網翻翻文件,我覺得學習一個模式或者框架的時候,最主要的是把主流程跑通,起碼可以符合標準的堆頁面,這樣的話,就可以把這玩意用起來,再遇到想要的什麼細節,就可以自己去翻文件,畢竟大體上已經懂了,寫過了幾個頁面,也有些體會,再去翻文件就很快能理解了。
### 庫
```dart
flutter_bloc: ^6.0.6 #狀態管理框架
equatable: ^1.2.3 #增強元件相等性判斷
```
- 看看flutter_bloc都推到6.0了,別再用StreamController手搭Bloc了!
### 外掛
在Android Studio設定的Plugins裡,搜尋:Bloc
![外掛搜尋](https://cdn.jsdelivr.net/gh/CNAD666/MyData/pic/flutter/blog/20200804152204.png)
安裝重啟下,就OK了
- 右擊相應的資料夾,選擇“Bloc Class”,我在main資料夾新建的,填入的名字:main,就自動生成下面三個檔案;:main_bloc,main_event,main_state;main_view是我自己新建,用來寫頁面的。
![新建bloc檔案](https://cdn.jsdelivr.net/gh/CNAD666/MyData/pic/flutter/blog/20200804152227.png)
![目錄結構新建bloc檔案](https://cdn.jsdelivr.net/gh/CNAD666/MyData/pic/flutter/blog/20200804152237.png)
- 是不是覺得,還在手動新建這些bloc檔案low爆了;就好像fish_redux,不用外掛,讓我手動去建立那六個檔案,寫那些模板程式碼,真的要原地爆炸。
## Bloc範例
### 初始化程式碼
來看下這三個生成的bloc檔案:main_bloc,main_event,main_state
- main_bloc:這裡就是咱們主要寫邏輯的頁面了
- mapEventToState方法只有一個引數,後面自動帶了一個逗號,格式化程式碼就分三行了,建議刪掉逗號,格式化程式碼。
```dart
class MainBloc extends Bloc {
MainBloc() : super(MainInitial());
@override
Stream mapEventToState(
MainEvent event,
) async* {
// TODO: implement mapEventToState
}
}
```
- main_event:這裡是執行的各類事件,有點類似fish_redux的action層
```dart
@immutable
abstract class MainEvent {}
```
- main_state:狀態資料放在這裡儲存,中轉
```dart
@immutable
abstract class MainState {}
class MainInitial extends MainState {}
```
### 實現
- 說明
- 這裡對於簡單的頁面,state的使用抽象狀態繼承實現的方式,未免有點麻煩,這裡我進行一點小改動,state的實現類別有很多,官網寫demo也有不用抽象類,直接class,類似實體類的方式開搞的。
- 老夫在程式碼關鍵點寫上"///"型別註釋,大家仔細看看,拷進Android Studio裡面,這些地方會變綠!大家好好體會下綠色程式碼!
- main_bloc
- state變數是框架內部定義的,會預設儲存上一次同步的MainSate物件的值
```dart
class MainBloc extends Bloc {
MainBloc() : super(MainState(selectedIndex: 0, isExtended: false));
@override
Stream mapEventToState(MainEvent event) async* {
///main_view中新增的事件,會在此處回撥,此處處理完資料,將資料yield,BlocBuilder就會重新整理元件
if (event is SwitchTabEvent) {
///獲取到event事件傳遞過來的值,咱們拿到這值塞進MainState中
///直接在state上改變內部的值,然後yield,只能觸發一次BlocBuilder,它內部會比較上次MainState物件,如果相同,就不build
yield MainState()
..selectedIndex = event.selectedIndex
..isExtended = state.isExtended;
} else if (event is IsExtendEvent) {
yield MainState()
..selectedIndex = state.selectedIndex
..isExtended = !state.isExtended;
}
}
}
```
- main_event:在這裡就能看見,view觸發了那些事件了;維護起來也很爽,看看這裡,也很快能懂頁面在幹嘛了
```dart
@immutable
abstract class MainEvent extends Equatable{
const MainEvent();
}
///切換NavigationRail的tab
class SwitchTabEvent extends MainEvent{
final int selectedIndex;
const SwitchTabEvent({@required this.selectedIndex});
@override
List