StreamBuilder介紹
前面介紹過(guò)FutureBuilder,它是一個(gè)Widget控件寥枝,提供了異步數(shù)據(jù)獲取與ui更新的能力井仰,StreamBuilder與FutureBuilder類似[官方文檔]恶守,也是一個(gè)Widget控件第献,不一樣的是FutureBuilder依靠Future來(lái)做異步數(shù)據(jù)獲取,而StreamBuilder則是依賴Stream來(lái)做異步數(shù)據(jù)獲取兔港。
Stream介紹
在講StreamBuilder前得先介紹下Stream這個(gè)東西庸毫。通俗點(diǎn)講,Stream就是個(gè)事件流衫樊,有點(diǎn)類似于RxJava飒赃,它允許我們從一端發(fā)射一個(gè)事件,從另外一端去監(jiān)聽(tīng)事件的變化科侈,通過(guò)Stream我們可以在Flutter上設(shè)計(jì)出基于事件流驅(qū)動(dòng)的響應(yīng)式代碼邏輯载佳。
Stream的簡(jiǎn)單實(shí)用
事實(shí)上Stream并是不Flutter的產(chǎn)物,而是由Dart提供的兑徘,Stream是一個(gè)抽象的接口刚盈,Dart提供了StreamController接口類可以讓我們方便的使用Stream,步驟大致如下:
- 創(chuàng)建
StreamController
- 獲取
StreamSink
用作發(fā)射事件 - 獲取
Stream
用作事件的監(jiān)聽(tīng) - 獲取
StreamSubscription
用作管理監(jiān)聽(tīng)挂脑,關(guān)閉暫停等
StreamSubscription<String> subscription;
//創(chuàng)建StreamController
var streamController = StreamController<String>();
// 獲取StreamSink用于發(fā)射事件
StreamSink<String> get streamSink => streamController.sink;
// 獲取Stream用于監(jiān)聽(tīng)
Stream<String> get streamData => streamController.stream;
//監(jiān)聽(tīng)事件
subscription = streamData.listen((value) {
// do something
});
//發(fā)射一個(gè)事件.
streamSink.add(index.toString());
StreamBuilder的使用介紹
- 構(gòu)造方法
StreamBuilder({Key key, T initialData, Stream<T> stream, @required AsyncWidgetBuilder<T> builder })
initialData
: 默認(rèn)初始化數(shù)據(jù)
stream
: stream事件流對(duì)象
builder
: 負(fù)責(zé)根據(jù)不同狀態(tài)創(chuàng)建對(duì)應(yīng)ui的方法實(shí)現(xiàn)
AsyncWidgetBuilder前面在講FutureBuilder的時(shí)候已經(jīng)介紹過(guò),這里不再贅述欲侮。
- 其他方法
afterConnected
:返回一個(gè)AsyncSnapshot崭闲,當(dāng)訂閱了stream時(shí)會(huì)回調(diào)此AsyncSnapshot
afterData
:返回一個(gè)AsyncSnapshot,當(dāng)stream有事件觸發(fā)時(shí)會(huì)回調(diào)此AsyncSnapshot
afterDisconnected
:返回一個(gè)AsyncSnapshot威蕉,當(dāng)取消訂閱stream時(shí)會(huì)回調(diào)此AsyncSnapshot
afterDone
:返回一個(gè)AsyncSnapshot刁俭,當(dāng)stream被關(guān)閉時(shí)會(huì)回調(diào)此AsyncSnapshot
afterError
:返回一個(gè)AsyncSnapshot,stream發(fā)生錯(cuò)誤時(shí)會(huì)回調(diào)此AsyncSnapshot
StreamBuilder 內(nèi)部已經(jīng)幫我們完成了stream的訂閱與取消訂閱韧涨,在initState的時(shí)候進(jìn)行事件的訂閱牍戚,在dispose的時(shí)候進(jìn)行事件的反訂閱侮繁,源碼在_StreamBuilderBaseState
里,關(guān)鍵過(guò)程大致如下
void initState() {
super.initState();
_summary = widget.initial();
_subscribe();
}
void dispose() {
_unsubscribe();
super.dispose();
}
void _subscribe() {
if (widget.stream != null) {
_subscription = widget.stream.listen((T data) {
setState(() {
_summary = widget.afterData(_summary, data);
});
}, onError: (Object error) {
setState(() {
_summary = widget.afterError(_summary, error);
});
}, onDone: () {
setState(() {
_summary = widget.afterDone(_summary);
});
});
_summary = widget.afterConnected(_summary);
}
}
void _unsubscribe() {
if (_subscription != null) {
_subscription.cancel();
_subscription = null;
}
}
從上面的源碼里面我們也可以清楚得看見(jiàn)StreamBuilder的各個(gè)回調(diào)方法的調(diào)用過(guò)程如孝。
完整例子
下面給出一個(gè)完整的代碼例子宪哩,我們的頁(yè)面在初始化的時(shí)候創(chuàng)建了StreamController
,頁(yè)面上面有個(gè)按鈕第晰,當(dāng)點(diǎn)擊按鈕的時(shí)候就會(huì)發(fā)射出一個(gè)事件锁孟,StreamBuilder訂閱了這個(gè)事件,并且把data打印出來(lái)
import 'dart:async';
import 'package:flutter/material.dart';
import 'dart:io';
import 'dart:convert';
/**
* Created by nls on 2019/7/20.
* Nothing.
*/
class StreamBuilderDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(primaryColor: Colors.blue),
home: HomeWidget());
}
}
class HomeWidget extends StatefulWidget {
@override
State createState() {
return HomeState();
}
}
class HomeState extends State<HomeWidget> {
var index = 0;
StreamSubscription<String> subscription;
//創(chuàng)建StreamController
var streamController;
// 獲取StreamSink用于發(fā)射事件
StreamSink<String> get streamSink => streamController.sink;
// 獲取Stream用于監(jiān)聽(tīng)
Stream<String> get streamData => streamController.stream;
void onFloatActionButtonPress() {
//發(fā)射一個(gè)事件.
streamSink.add(index.toString());
index++;
}
@override
void initState() {
super.initState();
streamController = StreamController<String>();
streamSink.add("0");
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('streamBuilder')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
StreamBuilder<String>(
stream: streamData,
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
return Text('Result: ${snapshot.data}');
}
)
],
)
),
floatingActionButton: FloatingActionButton(
onPressed: onFloatActionButtonPress,
child: Icon(Icons.add))
);
}
}