詳解Flutter中的數(shù)據(jù)傳遞
Flutter 中的數(shù)據(jù)傳遞
在開(kāi)發(fā)中,數(shù)據(jù)從一個(gè)頁(yè)面?zhèn)鬟f到另一個(gè)頁(yè)面事很常用的,在Android 開(kāi)發(fā)中,通常是通過(guò)把數(shù)據(jù)放到 intent 中傳遞過(guò)去。在 Flutter 中,數(shù)據(jù)是如何傳遞的呢?
在Flutter 中一切都是Widget,所以數(shù)據(jù)的傳遞就成了數(shù)據(jù)才Widget 中的傳遞。在之前的學(xué)習(xí)中,數(shù)據(jù)從一個(gè)Widget 傳遞到 子 Widget 是通過(guò)構(gòu)造函數(shù),一層一層的往里面?zhèn)?,要?widget 的層級(jí)比較少,還沒(méi)什么問(wèn)題,要是層級(jí)很多,這樣傳遞就太麻煩了。
還好Flutter 還提供了三種方案:InheritedWidget、Notification 和 EventBus來(lái)解決數(shù)據(jù)傳遞問(wèn)題。
InheritedWidget
InheritedWidget 是 Flutter 中的一個(gè)功能型 Widget,適用于在 Widget 樹(shù)中共享數(shù)據(jù)的場(chǎng)景。通過(guò)它,我們可以高效地將數(shù)據(jù)在 Widget 樹(shù)中進(jìn)行跨層傳遞。
下面看計(jì)數(shù)器的例子:
// 1.InheritedWidget,我們定義了一個(gè)繼承自它的新類 CountContainer,里面存放需要共享的數(shù)據(jù)
//然后,我們將計(jì)數(shù)器狀態(tài) count 屬性放到 CountContainer 中,并提供了一個(gè) of 方法方便其子 Widget 在 Widget 樹(shù)中找到它。
//最后,我們重寫(xiě)了 updateShouldNotify 方法,這個(gè)方法會(huì)在 Flutter 判斷 InheritedWidget 是否需要重建,
class CountContainer extends InheritedWidget {
static CountContainer of(BuildContext context) =>
context.dependOnInheritedWidgetOfExactType<CountContainer>();
final _InheritedWidgetHomeState mode;
final Function() function;
CountContainer(
{Key key,
@required this.mode,
@required this.function,
@required Widget child})
: super(key: key, child: child);
@override
bool updateShouldNotify(covariant InheritedWidget oldWidget) {
return this != oldWidget;
}
}
// 2. 通過(guò)構(gòu)建方法,把數(shù)據(jù)放到 InheritedWidget中
class _InheritedWidgetHomeState<InheritedWidgetHome> extends State {
int count = 0;
void _incrementCounter() => setState(() {
count++;
});
@override
Widget build(BuildContext context) {
return CountContainer(
mode: this,
function: _incrementCounter,
child: CountWidget(),
);
}
}
// 3. 在子 widget 通過(guò) CountContainer.of方法,獲取到自定義的 InheritedWidget,并從中取得共享的數(shù)據(jù)
class CountWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
CountContainer state = CountContainer.of(context);
return Scaffold(
appBar: AppBar(
title: Text("InheritedWidget demo"),
),
body: Text("current count is ${state.mode.count}"),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: state.function,
),
);
}
}
可以看到,InheritedWidget 的數(shù)據(jù)流動(dòng)方式是從父 Widget 到子 Widget 逐層傳遞。
- 首先把通過(guò)構(gòu)造函數(shù)需要共享的數(shù)據(jù)放到 InheritedWidget 中,然后提供一個(gè)靜態(tài)方法,返回自身;
- 然后在把自定義的 InheritedWidget做為父容器,傳入需要共享的數(shù)據(jù);
- 最后在子widget 中,通過(guò)靜態(tài)方法獲取到 InheritedWidget 對(duì)象,自然就拿到里面的數(shù)據(jù)了。
EventBus
無(wú)論是 InheritedWidget 還是 Notificaiton,它們的使用場(chǎng)景都需要依靠 Widget 樹(shù),在使用起來(lái)就有點(diǎn)極限了,但Flutter 提供了一個(gè)更好的數(shù)據(jù)傳遞方法--EventBus,傳遞數(shù)據(jù)不再受到限制了。
在原生開(kāi)發(fā)中,也有使用過(guò) 事件總線EventBus,F(xiàn)lutter 中實(shí)現(xiàn)跨組件通信的機(jī)制也是一樣。它遵循發(fā)布 / 訂閱模式,允許訂閱者訂閱事件,當(dāng)發(fā)布者觸發(fā)事件時(shí),訂閱者和發(fā)布者之間可以通過(guò)事件進(jìn)行交互。發(fā)布者和訂閱者之間無(wú)需有父子關(guān)系,甚至非 Widget 對(duì)象也可以發(fā)布 / 訂閱。這些特點(diǎn)與其他平臺(tái)的事件總線機(jī)制是類似的。
由于 EventBus是第三方庫(kù),所以需要引入:
event_bus: 2.0.0
從第二個(gè)頁(yè)面,把數(shù)據(jù)回傳到第一個(gè)頁(yè)面
//建立公共的event bus
EventBus eventBus = EventBus();
class CustomEvent {
String msg;
CustomEvent(this.msg);
}
class _EventBusPager1State extends State {
String message = "原來(lái)的數(shù)據(jù)";
StreamSubscription subscription;
@override
void initState() {
subscription = eventBus.on<CustomEvent>().listen((event) {
setState(() {
message = event.msg;
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("EventBusPager1"),
),
body: Center(
child: Text(message),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.open_in_browser),
onPressed: () => Navigator.push(
context, MaterialPageRoute(builder: (context) => EventBusPager2())),
),
);
}
@override
void dispose() {
subscription.cancel();
super.dispose();
}
}
class EventBusPager2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("EventBusPager2"),
),
body: Center(
child: Text("EventBusPager1"),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.send),
onPressed: () {
eventBus.fire(CustomEvent("data from page 2"));
Navigator.pop(context);
},
),
);
}
}

總結(jié)
通過(guò)學(xué)習(xí)了解了 在Flutter 中如何傳遞數(shù)據(jù)的,大致分為四種方式:
- 通過(guò)屬性,一層一層往下傳
- 通過(guò) 把數(shù)據(jù)寫(xiě)到 InheritedWidget的子類,然后把共享的數(shù)據(jù)放到里面,并提獲取自身的供靜態(tài)方法,在需要的地方通過(guò)靜態(tài)方法獲取到 InheritedWidget對(duì)象,并獲取數(shù)據(jù),這種方式是能從父widget 傳遞到子widget;
- 通過(guò) Notifaction 發(fā)送消息,然后再父 widget 進(jìn)行監(jiān)聽(tīng);
- 通過(guò)eventBus ,通過(guò)發(fā)布 / 訂閱模式,來(lái)完成數(shù)據(jù)的傳遞,也是開(kāi)發(fā)中常用的。
以上就是詳解Flutter中的數(shù)據(jù)傳遞的詳細(xì)內(nèi)容,更多關(guān)于Flutter中的數(shù)據(jù)傳遞的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android利用傳感器實(shí)現(xiàn)微信搖一搖功能
這篇文章主要為大家詳細(xì)介紹了Android利用傳感器實(shí)現(xiàn)微信搖一搖功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11
Android中怎樣避免創(chuàng)建不必要的對(duì)象
對(duì)象的創(chuàng)建從來(lái)都不是免費(fèi)的. 一個(gè)使用線程分配池的通用垃圾回收器可以讓臨時(shí)對(duì)象的分配變得廉價(jià)一些, 但是分配內(nèi)存總是比不分配要昂貴得多.所以避免創(chuàng)建不必要的對(duì)象是很重要的一方面。2016-08-08
Android使用動(dòng)畫(huà)設(shè)置ProgressBar進(jìn)度的方法
這篇文章主要為大家詳細(xì)介紹了Android使用動(dòng)畫(huà)設(shè)置ProgressBar進(jìn)度的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01
詳解Android平臺(tái)上讀寫(xiě)NFC標(biāo)簽
NFC,即Near Field Communication,近距離無(wú)線通訊技術(shù),是一種短距離的(通常<=4cm或更短)高頻(13.56M Hz)無(wú)線通信技術(shù),可以讓消費(fèi)者簡(jiǎn)單直觀地交換信息、訪問(wèn)內(nèi)容與服務(wù)。2017-01-01
LayoutAnimation給ListView中的item設(shè)置動(dòng)態(tài)出場(chǎng)效果(實(shí)例)
下面小編就為大家?guī)?lái)一篇LayoutAnimation給ListView中的item設(shè)置動(dòng)態(tài)出場(chǎng)效果(實(shí)例)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10
一分鐘快速定位Android啟動(dòng)耗時(shí)問(wèn)題
做開(kāi)發(fā)除了實(shí)現(xiàn)功能,還要注重優(yōu)化,性能優(yōu)化包括的東西還是非常多的,下面這篇文章主要給大家介紹了關(guān)于如何通過(guò)一分鐘快速定位Android啟動(dòng)耗時(shí)問(wèn)題的相關(guān)資料,需要的朋友可以參考下2021-07-07
Kotlin之在Gradle中無(wú)參(no-arg)編譯器插件的使用詳解
這篇文章主要介紹了Kotlin之在Gradle中無(wú)參(no-arg)編譯器插件的使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11

