在上篇文章Flutter之Stream、StreamController的使用(二)中我們用StatelessWidget實(shí)現(xiàn)了UI更新的效果,這不經(jīng)讓人好奇:StatelessWidget不是無法重新構(gòu)建嗎?看代碼發(fā)現(xiàn),UI更新是StreamBuilder實(shí)現(xiàn)的,我們來探究下它的原理。
StreamBuilder是 Flutter 中用于構(gòu)建基于流 (Stream) 的部件樹的一個 widget。它可以自動重新構(gòu)建其 UI 任何時間流發(fā)出新的數(shù)據(jù)。要理解 StreamBuilder 的內(nèi)部工作原理,我們可以探討以下幾個關(guān)鍵點(diǎn):
1. StreamBuilder 和 Stream
Stream 是 Dart 中的一個核心部分,它用于接收異步事件序列,這些事件可以包括數(shù)據(jù)消息或錯誤。
StreamBuilder 則是一個 widget,它能夠根據(jù)最新的 Stream快照 (snapshot) 來重建自己。
2. 如何工作
a. 訂閱Stream
當(dāng)你將一個 Stream 傳遞給 StreamBuilder,它開始 訂閱 這個流。這意味著每當(dāng)流發(fā)出一個新的值時,StreamBuilder 都會得到通知。
b. 構(gòu)建新的 Widget
每當(dāng) Stream發(fā)出一個新的值時,StreamBuilder 會調(diào)用其 builder 函數(shù),該函數(shù)會根據(jù)新的值重建UI。傳遞給 builder 函數(shù)的 AsyncSnapshot對象包含了流的當(dāng)前快照,包括數(shù)據(jù)、錯誤和連接狀態(tài)。
c. 更新 UI
一旦 builder 函數(shù)返回一個新的widget,StreamBuilder將更新其 UI,顯示新 widget。
d. 取消訂閱
當(dāng) StreamBuilder 被 dispose 時(例如,當(dāng)你切換頁面時),它自動取消訂閱 Stream,這防止了內(nèi)存泄漏。
3. 示例使用
StreamBuilder<String>(
stream: someStream,
initialData: 'Initial Data',
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading...');
default:
return Text('Data: ${snapshot.data}');
}
},
)
4. 效率
由于只有當(dāng) Stream發(fā)出新的值時 StreamBuilder才重建,所以它相當(dāng)效率高。
它避免了不必要的 UI 重建,只有當(dāng)實(shí)際的數(shù)據(jù)改變時,與數(shù)據(jù)有關(guān)的 UI部分才會被重建。
5. 常見問題
多次訂閱的處理:如果 Stream不支持多次訂閱,當(dāng) StreamBuilder 重新構(gòu)建并重新訂閱流時可能會遇到問題。為此,多訂閱(一對多,類似原生iOS里的通知)需要使用 BroadcastStream。
結(jié)論
StreamBuilder提供了一種優(yōu)雅的方式來動態(tài)更新UI,同時避免了不必要的渲染,將異步操作與 UI更新巧妙地結(jié)合在一起。了解其工作原理有助于你更加高效地利用它來構(gòu)建響應(yīng)式 UI。