flutter_bloc 是實現了 BLoC 模式的第三方庫,可以讓你很方便的使用 BLoC 模式開發 Flutter 應用。
Hi,大家好!我興奮的宣佈 flutter_bloc 釋出了最新的版本 v0.19.0,其中包含了社群要求的幾個特性,最重要的是提升了開發體驗和減少模板程式碼。
在介紹更新的特性之前,我想先感謝社群裡那些反饋使用體驗、建立 PR、和提 isuues 的人,如果沒有你們的共享的話,我們很難實現這些新特性。
廢話不多說,現在讓我們看看更新了哪些新特性!
BlocProvider 的改進
在此之前,為了初始化和回收 bloc,一般都會使用 StatefulWidget 來建立 bloc,因為 StatefulWidget 相比 StatelessWidget 自帶生命週期。但是這也導致了許多模板程式碼,而且也會帶來一些問題,例如很容易忘記釋放 bloc 或者在 build 方法裡初始化 bloc。為了解決這些問題,社群裡有人甚至建立了外掛,如 flutter_bloc_extensions 。我很高興的宣佈,這些的反饋已經被採納了,現在 BlockProvider
已經可以自動的釋放 blocs。
BlockProvider
現在有兩種使用方法。
第一種方法是使用預設的建構函式:
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
builder: (BuildContext context) => MyBloc(),
child: MyChild(),
);
}
}
複製程式碼
在此之前,你只能這麼寫:
class MyWidget extends StatefulWidget {
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
MyBloc _myBloc;
@override
void initState() {
super.initState();
_myBloc = MyBloc();
}
@override
Widget build(BuildContext context) {
return BlocProvider(
bloc: _myBloc,
child: MyChild(),
);
}
@override
void dispose() {
_myBloc.dispose();
super.dispose();
}
}
複製程式碼
你可以看到,在此之前,需要使用 StatefulWidget 來寫 bloc,但現在只需要使用 StatelessWidget 就可以了,實現 bloc 的程式碼量大幅減少,而且會自動釋放 bloc,所以不用擔心 bloc 的釋放問題。
第二種方法是使用 BlocProvider
的 value
建構函式:
Navigator.of(context).push(
MaterialPageRoute<MyPage>(
builder: (context) {
return BlocProvider.value(
value: BlocProvider.of<MyBloc>(context),
child: MyPage(),
);
},
),
);
複製程式碼
在上面的例子中,把一個已經存在的 MyBloc
例項給 MyPage
使用,MyPage
是一個新頁面,使用 Navigator
開啟。在這個例子裡,我們要為 MyPage
提供一個已經存在的 MyBloc
例項,並且不希望釋放 MyBloc
當 MyPage
頁面關閉的時候,因為還有其他地方在使用 MyBloc
。所以,我們可以使用 BlocProvider
的 value
建構函式為 Widget 提供一個已經存在的 bloc 並且不會自動釋放。可以點選 route_access_recipe 檢視更多。
總結一下,如果你要建立一個新的 bloc 給子樹使用,就可以使用 BlocProvider
的預設建構函式來建立 bloc 例項,會有自動釋放 bloc 的功能。但是如果只是要給子樹提供一個已經存在的 bloc 例項,這個時候就不需要自動釋放 bloc 的功能,所以使用 BlocProvider
的 value
建構函式。想要釋放 bloc 的話,就在建立 bloc 的地方釋放。
你現在就不需要使用 StatefulWidget
來管理你的 blocs 了。
MultiBlocProvide(之前是 BlocProviderTree)
MultiBlocProvide
的功能是把多個 BlocProvider
合併到一起。
MultiBlocProvide
因為消除了多個 BlocProvider
的巢狀,所以提高了程式碼的可讀性。
在此之前,多個 BlocProvider
是這麼寫的:
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider<BlocA>(
builder: (BuildContext context) => BlocA(),
child: BlocProvider<BlocB>(
builder: (BuildContext context) => BlocB(),
child: BlocProvider<BlocC>(
builder: (BuildContext context) => BlocC(),
child: ChildA(),
)
),
);
}
}
複製程式碼
有了 MultiBlocProvide
,就可以這麼寫:
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<BlocA>(
builder: (BuildContext context) => BlocA(),
),
BlocProvider<BlocB>(
builder: (BuildContext context) => BlocB(),
),
BlocProvider<BlocC>(
builder: (BuildContext context) => BlocC(),
),
],
child: ChildA(),
);
}
}
複製程式碼
在上面的例子裡,我們為 ChildA
提供了 BlocA
,BlocB
,BlocC
三個 bloc。使用 MultiBlocProvider
可以無需額外的巢狀,可以讓我們的程式碼更好讀。
Repository Provider (之前是 ImmutableProvider)
Repository Provider
是新引進來的 provider,專門用於在 widget 樹中處理 repositories, repositories 用於處理資料請求,類似於 Redux 中的 Middleware。想要知道 repository 是什麼和怎麼用的,可以點選這裡檢視。
從架構上看,repository 是一個或多個 data providers 的封裝,並且負責與 bloc 通訊。所以,在整個 Widget 樹裡能訪問 repositories 是非常重要的,隨著最近的更新,這個功能很容易就能實現。
我們可以使用 RepositoryProvider
預設的建構函式建立和提供 repository:
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RepositoryProvider(
builder: (context) => MyRepository(),
child: MyChild(),
);
}
}
class MyChild extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
builder: (context) => MyBloc(RepositoryProvider.of<MyRepository>(context)),
child: MyOtherChild(),
);
}
}
複製程式碼
在上面的例子中,我們為 MyChild
及其子樹 建立了 MyRepository
的例項。然後在接下來的 Widget 樹裡建立的 MyBloc
(MyBloc
依賴 MyRepository
) 可以使用 RepositoryProvider.of
訪問 MyRepository
的例項。你會發現 MyRepository
的 API 和 BlocProvider
非常像,這樣的話就會更加容易使用。
MultiRepositoryProvider (過去是 ImmutableProviderTree)
MultiRepositoryProvider
的功能是把多個 RepositoryProvider
合併到一起。
MultiRepositoryProvider
因為消除了多個 RepositoryProvider
的巢狀,所以提高了程式碼的可讀性。
在此之前,多個 RepositoryProvider
是這麼寫的:
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RepositoryProvider<RepositoryA>(
builder: (context) => RepositoryA(),
child: RepositoryProvider<RepositoryB>(
builder: (context) => RepositoryB(),
child: RepositoryProvider<RepositoryC>(
builder: (context) => RepositoryC(),
child: ChildA(),
)
)
);
}
}
複製程式碼
有了 MultiRepositoryProvider
,就可以這麼寫:
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiRepositoryProvider(
providers: [
RepositoryProvider<RepositoryA>(
builder: (context) => RepositoryA(),
),
RepositoryProvider<RepositoryB>(
builder: (context) => RepositoryB(),
),
RepositoryProvider<RepositoryC>(
builder: (context) => RepositoryC(),
),
],
child: ChildA(),
);
}
}
複製程式碼
在上面的例子裡,我們為 ChildA
提供了 RepositoryA
,RepositoryB
,RepositoryC
。使用 MultiRepositoryProvider
可以無需額外的巢狀,可以讓我們的程式碼更好讀。
整合 Provider
你可能注意到,新的 BlocProvider
和 RepositoryProvider
的 API 和 Provider 很像。v0.19.0 的最大更新就是底層使用了 Provider,這樣開發者就可以擁有一個具有一致 API 的依賴注入庫。在這裡特別感謝 Remi Rousselet 的反饋和耐心。
flutter_bloc 還會繼續吸收接納其他的 providers(因為 flutter_bloc 會接受社群裡的其他反饋),但是我們非常激動在底層使用 Provider,這樣的話我們就不需要使用之前 我們自己的 InheritedWidget 的封裝,不需要自己來維護,而是直接享受到 Provider 未來更新帶來的新特性。
你可以檢視我們完整的 change_log 來檢視更多的資訊。