Streambuilder 渲染两次,第一次使用初始数据,第二次使用正确数据,但小部件不更新
Posted
技术标签:
【中文标题】Streambuilder 渲染两次,第一次使用初始数据,第二次使用正确数据,但小部件不更新【英文标题】:Streambuilder render twice, the first time with initial data the second one with correct data, but the widget doesn't update 【发布时间】:2020-10-20 05:21:59 【问题描述】:您好,我是 Flutter 的新手,我在状态方面遇到了麻烦。我正在使用 Bloc 来处理状态,但是当我尝试在第一个视图中设置状态时,我无法在第二个视图中显示它。
在第二个视图中,streambuilder 首先显示初始值和连接等待,然后获取正确的数据并将状态更改为活动,但小部件不更新。
第一次查看
class LoginScreen extends StatefulWidget
LoginScreen(Key key, this.title) : super(key: key);
final String title;
@override
_LoginScreenState createState() => _LoginScreenState();
class _LoginScreenState extends State<LoginScreen>
Widget _divider()
return Container(
margin: EdgeInsets.symmetric(vertical: 10),
child: Row(
children: <Widget>[
SizedBox(
width: 30,
),
Expanded(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 30),
child: Divider(
thickness: 1,
),
),
),
SizedBox(
width: 20,
),
],
),
);
final _emailController = TextEditingController();
final _passwordController =TextEditingController();
_updateEmail (String text) => userBloc.updateUser(text);
Widget _emailPasswordWidget()
return Column(
children: <Widget>[
EntryFields("Ingresa tu email", value:_emailController, onchanged: _updateEmail),
EntryFields("Ingresa tu Password",value: _passwordController, isPassword: true),
],
);
_goSignupScreen() async return Navigator.pushNamed(context, Routes.signupRoute );
_goHomeScreen() async
_updateEmail(_emailController.text);
return Navigator.pushNamed(context, Routes.homeRoute );
@override
Widget build(BuildContext context)
final height = MediaQuery.of(context).size.height;
return Scaffold(
body: Container(
height: height,
child: Stack(
children: <Widget>[
Positioned(
top: -height * .15,
right: -MediaQuery.of(context).size.width * .4,
child: BezierContainer()),
Container(
padding: EdgeInsets.symmetric(horizontal: 20),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(height: height* 0.2),
Center(child: AppIconWidget(image: 'assets/images/logo.png', scale: 0.1)),
SizedBox(height: 50),
_emailPasswordWidget(),
SizedBox(height: 20),
SubmitButton(title: 'Iniciar Sesión', onPressed: _goHomeScreen ),
Container(
padding: EdgeInsets.symmetric(vertical: 10),
alignment: Alignment.centerRight,
child: Text('Olvidaste tu contraseña?',
style: TextStyle(
fontSize: 14, fontWeight: FontWeight.w500)),
),
_divider(),
FacebookSignInButton(onPressed: ()),
GoogleSignInButton(onPressed: () ),
SizedBox(height: height * .055),
AccountLabel(label: 'No tienes cuenta?', btnText: 'Registrate', onPressed: _goSignupScreen ),
],
),
),
),
// Positioned(top: 40, left: 0, child: BackBtn() ),
],
),
),);
集团
class UserBloc
final _userRepository = UserRepository();
final _userController = PublishSubject();;
Observable get getUser => _userController.stream;
updateUser(user) async
var currentUser = await _userRepository.updateCurrentUser(user);
_userController.sink.add(currentUser);
return null;
dispose()
_userController.close();
final userBloc = UserBloc();
提供者
class UserProvider
Future updateCurrentUser(user) async
return currentUser = user;
存储库
class UserRepository
final userProvider = UserProvider();
Future updateCurrentUser(user)
return userProvider.updateCurrentUser(user);
第二次查看
class HomeScreen extends StatelessWidget
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(title: Text('title')),
body: StreamBuilder(
initialData: 'here!',
stream: userBloc.getUser,
builder: (BuildContext context, AsyncSnapshot snapshot)
print('...');
print('$snapshot.data');
print('$snapshot.connectionState');
print('...');
if (snapshot.hasError) return Text('Error: $snapshot.error');
switch (snapshot.connectionState)
case ConnectionState.none:
return Text('Select lot');
case ConnectionState.waiting:
return Text('Awaiting bids...');
case ConnectionState.active:
return Text('\$$snapshot.data');
case ConnectionState.done:
return Text('\$$snapshot.data (closed)');
return null; // unreachable
,
),
);
谢谢!
【问题讨论】:
【参考方案1】:我认为最好使用 snapshot.hasData,而不是为 connectionState 进行切换
if (snapshot.hasData)
return Text('\$$snapshot.data');
else
return Text('Loading;);
【讨论】:
我做到了,但它只渲染初始数据(这里!),但是当我看到日志时,我看到状态正在更新 I/flutter (21519): ... I/扑动(21519):在这里! I/flutter (21519): ConnectionState.waiting I/flutter (21519): ... I/flutter (21519): ... I/flutter (21519): 12345 I/flutter (21519): ConnectionState.active I/颤动(21519):...以上是关于Streambuilder 渲染两次,第一次使用初始数据,第二次使用正确数据,但小部件不更新的主要内容,如果未能解决你的问题,请参考以下文章
在 StreamBuilder 中渲染 ListView.ListTile
导航到该组件后反应功能组件渲染两次,但是在尝试刷新时,仅渲染一次
Flutter 中的 StreamBuilder 卡在 ConnectionState.waiting 中并且只显示加载标记