Flutter中Google SignIn验证后传用户邮箱至其他页面的实现疑问
Hey there! Let's break down your problem and fix this properly. Your current setup has a few key issues—like the Scaffold not waiting for mostraUID() to finish, and calling setState() directly in build() which can trigger infinite loops. Let's tackle this step by step using Flutter's best practices for async operations and Firebase Auth.
1. Using Future/Async for Authentication Logic
Your mostraUID() function is on the right track, but relying on a one-time Future in initState isn't the most reliable way. A better approach is to listen to Firebase Auth's user state stream—this automatically updates your UI whenever the user logs in, logs out, or their credentials change, which is far more robust than a single async call.
2. Making Scaffold Wait for Authentication
Instead of trying to "wait" for mostraUID() to complete, we'll use StreamBuilder to build the UI conditionally based on the authentication state. This lets us show a loading state until user data is ready, then switch to the appropriate UI (login prompt or logged-in view).
3. Optimal Implementation
Here's a refactored version of your code that solves all your issues, including safely getting the user's email for your Firebase database reference:
import 'package:flutter/material.dart'; import 'package:google_sign_in/google_sign_in.dart'; import 'package:firebase_auth/firebase_auth.dart'; final googleSignIn = GoogleSignIn(); final auth = FirebaseAuth.instance; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return const MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), home: MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; // Dedicated async function for Google Sign-In Future<void> _signInWithGoogle() async { try { final GoogleSignInAccount? googleUser = await googleSignIn.signIn(); if (googleUser == null) return; // User canceled the sign-in flow final GoogleSignInAuthentication googleAuth = await googleUser.authentication; final AuthCredential credential = GoogleAuthProvider.credential( accessToken: googleAuth.accessToken, idToken: googleAuth.idToken, ); await auth.signInWithCredential(credential); // No manual state updates needed—StreamBuilder handles UI changes automatically } catch (e) { print('Sign-in error: $e'); // Add a snackbar or alert here to notify the user of the error } } void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { // Use StreamBuilder to listen to real-time auth state changes return StreamBuilder<FirebaseUser>( stream: auth.onAuthStateChanged, // Emits current user when state updates builder: (context, snapshot) { // Handle loading state while checking auth status if (snapshot.connectionState == ConnectionState.waiting) { return const Scaffold( body: Center(child: CircularProgressIndicator()), ); } // User is not logged in—show login prompt if (!snapshot.hasData || snapshot.data == null) { return Scaffold( appBar: AppBar(title: Text(widget.title)), body: const Center(child: Text('Please log in to continue')), floatingActionButton: FloatingActionButton( onPressed: _signInWithGoogle, tooltip: 'Sign in with Google', child: const Icon(Icons.login), ), ); } // User is logged in—access their data safely final FirebaseUser user = snapshot.data!; final String userEmail = user.email ?? 'No email found'; // Now you can safely use userEmail to build your Firebase database reference // Example: final databaseRef = FirebaseDatabase.instance.reference().child('messages/$userEmail'); return Scaffold( appBar: AppBar( title: Text(userEmail), // Display user's email in the app bar ), body: Center( child: Text('Button tapped $_counter time${_counter == 1 ? '' : 's' }.'), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: const Icon(Icons.add), ), ); }, ); } }
Key Improvements:
- No global state: We removed the global
_loggedUservariables (they're unnecessary and can cause inconsistent state) and get user data directly from theStreamBuildersnapshot. - Real-time updates: The
auth.onAuthStateChangedstream automatically refreshes the UI when the user logs in/out or their account changes—no manual state management needed. - Proper state handling: We show a loading indicator while checking auth status, a login prompt if the user isn't authenticated, and the main UI once logged in.
- Safe data access: Null checks (
?? 'No email found') handle cases where the user's email might be missing. - Cleaner code: Sign-in logic is isolated to a dedicated function, making the code easier to maintain and debug.
Quick Tips for Flutter/Firebase Beginners:
- Never call
setState()insidebuild()—this triggers an infinite loop becausebuild()runs every time state changes. - For newer Firebase versions, use
auth.authStateChanges()instead ofonAuthStateChanged(it's the updated API). - If you need to fetch additional data from Firebase Database once the user is logged in, nest a
FutureBuilderinside the logged-in section of theStreamBuilder.
内容的提问来源于stack exchange,提问作者Colque Paxi

