如何在Flutter中使用StreamBuilder从Firestore获取数据?
Fixing StreamBuilder to Fetch Firestore Data in Flutter
Hey there! I see you're trying to use StreamBuilder to pull data from Firestore and display it with your Lost_Card widget. Let's walk through fixing your code step by step to make it work properly.
First, Let's Address the Issues in Your Original Code
- Your
map()usage is incorrect—you need to iterate over each document in the snapshot and extract fields properly. - You're trying to return a single
Lost_Card, but your widget is built to display a grid, so we need to generate multiple cards from all Firestore documents. - You aren't handling snapshot states like loading or errors, which is critical for a smooth user experience.
Modified Complete Code
Here's the updated code that properly fetches and displays Firestore data:
import 'package:flutter/material.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; class LostPage extends StatefulWidget { @override _LostPage createState() => new _LostPage(); } class _LostPage extends State<LostPage> { //temp vars final String firebasetest = "Test"; //firestore vars final DocumentReference documentReference = Firestore.instance.document("Items/Rusty"); //CRUD operations void _add() { Map<String, String> data = <String, String>{ "name": firebasetest, "desc": "Flutter Developer", "url": "https://i.imgur.com/FtaGNck.jpg", // Added URL for testing "noro": "old" // Added noro field for card display }; documentReference.setData(data).whenComplete(() { print("Document Added"); }).catchError((e) => print(e)); } @override Widget build(BuildContext context) { return Scaffold( body: StreamBuilder( stream: Firestore.instance.collection('Items').snapshots(), builder: (_, AsyncSnapshot<QuerySnapshot> snapshot) { // Handle loading state if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } // Handle error state if (snapshot.hasError) { return Center(child: Text('Error: ${snapshot.error}')); } // Handle empty state if (!snapshot.hasData || snapshot.data.documents.isEmpty) { return const Center(child: Text('No items found')); } // Extract documents from snapshot final items = snapshot.data.documents; // Return GridView with Lost_Card for each Firestore item return GridView.count( shrinkWrap: true, crossAxisCount: 2, children: items.map((doc) { // Extract fields from Firestore document (add defaults for safety) final url = doc['url'] ?? ''; final title = doc['name'] ?? 'No Title'; final noro = doc['noro'] ?? 'New'; return Lost_Card( headImageAssetPath: url, title: title, noro: noro, ); }).toList(), ); }, ), floatingActionButton: FloatingActionButton( child: const Icon(Icons.add), onPressed: _add, ), ); } } class Lost_Card extends StatelessWidget { //All the card variables final String headImageAssetPath; final IconData icon; final Color iconBackgroundColor; final String title; final String noro; final int price; final ShapeBorder shape; Lost_Card({ this.headImageAssetPath, this.icon, this.iconBackgroundColor, this.title, this.noro, this.price, }); @override Widget build(BuildContext context) { return Card( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Expanded( child: Stack( fit: StackFit.expand, children: <Widget>[ Container( height: MediaQuery.of(context).size.height / 4, width: MediaQuery.of(context).size.height / 2.5, child: DecoratedBox( decoration: BoxDecoration( image: DecorationImage( image: NetworkImage(headImageAssetPath), fit: BoxFit.cover, ), ), ), ), Padding( padding: const EdgeInsets.all(8.0), child: Align( alignment: FractionalOffset.topLeft, child: CircleAvatar( backgroundColor: Colors.redAccent, radius: 15.0, child: Text( noro, textScaleFactor: 0.5, ), ), ), ), Align( alignment: FractionalOffset.topRight, child: Container( color: Colors.blueAccent, height: 35.0, width: 35.0, child: const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Icon(Icons.account_circle), Text( "1P", textScaleFactor: 0.5, ), ], ), ), ), ), ], ), ), Center( child: Container( padding: const EdgeInsets.all(8.0), alignment: FractionalOffset.bottomCenter, child: Text( title, style: const TextStyle( fontWeight: FontWeight.w700, ), ), ), ), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[ FlatButton( child: Text( "Add To Cart", style: TextStyle(color: Colors.grey[500]), ), onPressed: () => null, ), const Text( "\$5", style: TextStyle(color: Colors.grey[500]), ) ], ) ], ), ); } }
Key Changes Explained
- Snapshot State Handling: Added checks for loading, error, and empty states to keep the UI responsive and informative.
- Document Iteration: Used
items.map()to loop through each Firestore document, extract fields likeurl,name, andnoro, and create aLost_Cardfor each entry. - GridView Structure: Moved the GridView logic from
Lost_Cardto the StreamBuilder's builder function—this lets us generate multiple cards dynamically from Firestore data. - Field Safety: Used
??to provide default values if a field is missing in a Firestore document, preventing unexpected crashes.
Firestore Database Structure

Expected App Output

内容的提问来源于stack exchange,提问作者JackyBoi
相关产品推荐
相关产品推荐

