考虑以下代码:
StreamBuilder<QuerySnapshot> _createDataStream(){
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection("data").limit.(_myLimit).snapshots(),
builder: (context, snapshot){
return Text(_myLimit.toString);
}
);
}
我希望_myLimit
变量更改时StreamBuilder刷新。
可能会这样:
void _incrementLimit(){
setState(() =>_myLimit++);
}
我的问题是,除了setState((){});
之外,还有没有其他更快的方法。
因为当build()
变量更改时,我不想重新调用整个_myLimit
方法。
我想出了另一种方法,但是我觉得有更好的解决方案,因为我认为我没有使用.periodic
功能,并且嵌套了Stream,所以我不确定这是多么平常:
Stream<int> myStream = Stream.periodic(Duration(), (_) => _myLimit);
...
@override
Widget build(BuildContext context){
...
return StreamBuilder<int>(
stream: myStream,
builder: (context, snapshot){
return _createDataStream;
},
),
...
}
解决方案
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return new _MyAppState();
}
}
class _MyAppState extends State<MyApp> {
int myNum = 0;
final StreamController _myStreamCtrl = StreamController.broadcast();
Stream get onVariableChanged => _myStreamCtrl.stream;
void updateMyUI() => _myStreamCtrl.sink.add(myNum);
@override
void initState() {
super.initState();
}
@override
void dispose() {
_myStreamCtrl.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child:
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
StreamBuilder(
stream: onVariableChanged,
builder: (context, snapshot){
if(snapshot.connectionState == ConnectionState.waiting){
updateMyUI();
return Text(". . .");
}
return Text(snapshot.data.toString());
},
),
RaisedButton(
child: Text("Increment"),
onPressed: (){
myNum++;
updateMyUI();
},
)
],
),
)));
}
}
其他一些想法,StreamBuilder的外观也是如此:
StreamBuilder(
stream: onVariableChanged,
builder: (context, snapshot){
if(snapshot.connectionState == ConnectionState.waiting){
return Text(myNum.toString());
}
return Text(snapshot.data.toString());
},
),
StreamBuilder(
stream: onVariableChanged,
initialData: myNum,
builder: (BuildContext context, AsyncSnapshot snapshot){
if(snapshot.data == null){
return Text("...");
}
return Text(snapshot.data.toString());
},
),
答案 0 :(得分:5)
用StreamController
声明一个broadcast
,然后将此Stream
的{{1}}设置一个友好的名称,然后每次您要重建包装的小部件时( StreamController
只需使用StreamBuilder
的{{1}}属性来sink
一个新值,它将触发StreamController
。
您可以使用add
和StreamBuilder
,而无需设置类型。
但是,如果在键入StreamBuilder
时使用AsyncSnapshot
和StreamBuilder<UserModel>
,则会看到AsyncSnapshot<UserModel>
中的所有变量和方法。
snapshot.data.
这样,您可以使用UserModel
和final StreamController<UserModel> _currentUserStreamCtrl = StreamController<UserModel>.broadcast();
Stream<UserModel> get onCurrentUserChanged => _currentUserStreamCtrl.stream;
void updateCurrentUserUI() => _currentUserStreamCtrl.sink.add(_currentUser);
StreamBuilder<UserModel>(
stream: onCurrentUserChanged,
builder: (BuildContext context, AsyncSnapshot<UserModel> snapshot) {
if (snapshot.data != null) {
print('build signed screen, logged as: ' + snapshot.data.displayName);
return blocs.pageView.pagesView; //pageView containing signed page
}
print('build login screen');
return LoginPage();
//print('loading');
//return Center(child: CircularProgressIndicator());
},
)
(例如,具有不同颜色的图标)StatelessWidget
(用于重建整个页面)。
为了提高性能,流是最好的方法。
编辑:
我正在使用refresh just a single sub-widget
方法,因此最好在homePageBloc.dart(具有所有业务逻辑的常规控制器类)中声明变量,并在homePage.dart(具有类)中创建StreamBuilder扩展了无状态/有状态小部件并负责UI)。
编辑:我的without using setState
,如果您正在使用Firebase中的Cloud Firestore数据库,则可以使用BLoC architecture
代替UserModel.dart
。
DocumentSnapshot