Flutter技术问询:从Firebase Firestore获取指定数据并动态显示
Hey there! Let's work through this step by step—async data fetching can feel tricky when you're new to Flutter and Firebase, so let's break down the issues in your code and get that handle showing up in your AppBar.
1. First, Fix the Data Retrieval Method in database.dart
Looking at your retrieveData function, you're accidentally fetching the name field instead of handle! Plus, we should add some safety checks to avoid null errors:
Future<String> retrieveData(String uid) async { DocumentSnapshot snap = await users.document(uid).get(); // Check if the document exists first to avoid crashes if (snap.exists) { // Fallback to empty string if handle is null return snap.data['handle'] as String? ?? ''; } return ''; // Return empty if document doesn't exist }
You can also clean up the getUserData method since it has a wonky return type (Set<Set<String>> doesn't make sense here) — either fix it or comment it out for now to avoid confusion.
2. Use FutureBuilder to Fetch Data and Update the AppBar
Fetching data from Firestore is an async operation, which means your code doesn't wait for the data to come back before building the UI. Your original approach of using .then() won't trigger a UI update, so we'll use FutureBuilder to handle the loading, success, and error states:
Update your Profile widget's build method like this:
@override Widget build(BuildContext context) { User user = Provider.of<User>(context); return Scaffold( // Wrap the AppBar in FutureBuilder to wait for Firestore data appBar: FutureBuilder<String>( future: databaseMethods.retrieveData(user.uid), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { // Show a loading state while fetching data return AppBar(title: const Text('Loading...')); } else if (snapshot.hasError) { // Handle any errors that occur return AppBar(title: const Text('Oops, Error!')); } else { // Once data is ready, display the handle final handle = snapshot.data ?? ''; return AppBar(title: Text(handle)); } }, ), body: Container( // Keep your existing body content here—no changes needed! padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 50), child: Form( key: formKey, child: Column( children: <Widget>[ Image.asset('assets/profilepicture.png', height: 300, width: 300), const SizedBox(height: 20), // ... rest of your form fields and buttons ], ), ), ), ); }
3. Refresh the AppBar After Updating Data
Right now, when you click the Update button, the AppBar won't automatically show the new handle. Let's fix that by triggering a rebuild with setState:
Modify your Update button's onPressed callback:
onPressed: () async { if(formKey.currentState.validate()) { print(user.uid); await databaseMethods.updateSpecificUserData(user.uid, name, handle); setState(() { error = 'Update successful!'; // Calling setState will trigger the FutureBuilder to refetch data }); } },
This way, after updating the handle in Firestore, the page rebuilds, and the FutureBuilder fetches the latest data to display in the AppBar.
Why Your Original Code Didn't Work
The issue with your initial approach:
Future<String> str = databaseMethods.retrieveData(user.uid); str.then((value) => { handle = value }); print(handle);
Is that retrieveData runs asynchronously—your print(handle) line executes before the data comes back from Firestore, so it prints an empty string. Even if the assignment worked, you didn't call setState to tell Flutter to update the UI. FutureBuilder handles both the async waiting and UI updates for you.
内容的提问来源于stack exchange,提问作者Rishi

