Flutter应用Stream初始状态异常及Google登录后用户名不显示问题
解决你的Google登录Stream状态与UI更新问题
嘿,刚上手Dart和Flutter的第一个应用对吧?我帮你梳理下遇到的两个问题,咱们一步步来解决:
问题1:初始Stream状态为ConnectionState.waiting而非none
你现在的_currentUser变量一开始是未初始化的(默认null),当StreamBuilder拿到null的stream时,就会默认进入ConnectionState.waiting状态。要让初始状态变成none,咱们只需要在初始化的时候给_currentUser赋值一个空的Stream就行。
问题2:登录成功后无法立即显示用户名
你点击登录按钮时直接给_currentUser赋值了新的Stream,但没有触发Widget的重建——Flutter只有在调用setState的时候才会重新执行build方法更新UI,所以你的StreamBuilder根本没机会监听新的用户数据流,自然不会显示用户名。咱们需要把赋值操作放到setState里。
修改后的完整代码
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:google_sign_in/google_sign_in.dart'; final FirebaseAuth _auth = FirebaseAuth.instance; final GoogleSignIn _googleSignIn = GoogleSignIn(); class HomePage extends StatefulWidget { static String tag = 'home-page'; @override HomePageState createState() { return HomePageState(); } } class HomePageState extends State<HomePage> { // 初始化空Stream,让初始状态为ConnectionState.none Stream<FirebaseUser> _currentUser = Stream.empty(); Future<FirebaseUser> signInWithGoogle() async { print('google signin invoked'); GoogleSignInAccount googleUser = await _googleSignIn.signIn(); GoogleSignInAuthentication googleAuth = await googleUser.authentication; FirebaseUser user = await _auth.signInWithGoogle( accessToken: googleAuth.accessToken, idToken: googleAuth.idToken, ); print("signed in " + user.displayName); return user; } @override Widget build(BuildContext context) { final lblWelcome = Padding( padding: EdgeInsets.all(8.0), child: Text('Frnds Payment', style: TextStyle(fontSize: 28.0, color: Colors.green)) ); final btnSignin = MaterialButton( child: const Text('Sign In with Google'), onPressed: () async { print('button clicked'); // 用setState触发UI更新,让StreamBuilder监听新的Stream setState(() { _currentUser = signInWithGoogle().asStream(); }); } ); final txtOutput = StreamBuilder<FirebaseUser>( stream: _currentUser, builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot) { switch (snapshot.connectionState) { case ConnectionState.none: // 初始状态会走到这里,显示提示文字或者空布局 return Text('请点击按钮登录'); case ConnectionState.waiting: return Center(child: CircularProgressIndicator()); default: if (snapshot.hasError) return Text('Error: ${snapshot.error}'); else return Center(child: Text('欢迎你,${snapshot.data.displayName}')); } } ); final body = Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[lblWelcome, btnSignin, txtOutput], ), ); return Scaffold(body: body); } }
关键修改点说明
- 初始化Stream:把
Stream<FirebaseUser> _currentUser;改成Stream<FirebaseUser> _currentUser = Stream.empty();,这样初始时StreamBuilder的connectionState就是none,你可以在这个状态下显示“请点击按钮登录”之类的提示,比加载圈更友好。 - 用setState更新Stream:在登录按钮的
onPressed里,把_currentUser = signInWithGoogle()?.asStream();放到setState回调里,这样Flutter会知道状态变了,重新构建Widget,StreamBuilder就能拿到新的用户数据并显示用户名了。
这样修改后,你打开应用初始状态会显示提示文字,点击登录后显示加载圈,登录成功后立刻显示用户名,完全符合你的需求啦~
内容的提问来源于stack exchange,提问作者Rahul Somasundaram
相关产品推荐
相关产品推荐

