Flutter桌面应用Firebase Firestore插件平台线程异常问题
我用Flutter开发桌面应用,通过Stream Builder加载Firebase Firestore数据库中的所有记录。但启动应用时无法加载任何数据,且抛出平台线程异常;从其他页面导航至使用Stream Builder的首页时,有时可正常工作。
异常信息
[ERROR:flutter/shell/common/shell.cc(1015)] The 'plugins.flutter.io/firebase_firestore/query/e908a231-bed2-4607-bf64-d5c76972c0dd' channel sent a message from native to Flutter on a non-platform thread. Platform channel messages must be sent on the platform thread. Failure to do so may result in data loss or crashes, and must be fixed in the plugin or application code creating that channel.
相关代码
homescreen.dart
import 'package:admin/productdetails.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; class homescreen extends StatefulWidget { static const String home = './homescreen'; const homescreen({super.key}); @override State<homescreen> createState() => _homescreenState(); } class _homescreenState extends State<homescreen> { @override Widget build(BuildContext context) { double screenWidth = MediaQuery.of(context).size.width; double screenHeight = MediaQuery.of(context).size.height; Color customColor = HexColor("#fd7b2e"); return Scaffold( body: Container( decoration: const BoxDecoration( image: DecorationImage( image: AssetImage('assets/home.png'), fit: BoxFit.cover, ), ), child: Stack( children: [ Container( alignment: Alignment.topCenter, width: double.infinity, child: Text( 'ADMIN', style: GoogleFonts.getFont( 'Oswald', textStyle: TextStyle( fontSize: screenWidth * 0.04, fontWeight: FontWeight.bold, color: Colors.white), ), ), ), Stack( children: [ Padding( padding: EdgeInsets.only( top: screenWidth * 0.1, left: screenWidth * 0.01, ), child: Container( height: screenWidth * 0.4, width: screenWidth * 0.29, decoration: const BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(20)), color: Colors.white70, ), child: Column( children: [ Builder( builder: (BuildContext context) { return SingleChildScrollView( child: Container( child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'New Orders', style: GoogleFonts.getFont( 'Outfit', textStyle: TextStyle( fontSize: screenWidth * 0.02, fontWeight: FontWeight.bold, ), ), ), ], ), SizedBox( height: screenHeight * 0.5, child: StreamBuilder<QuerySnapshot>( stream: FirebaseFirestore.instance .collection('orders') .snapshots(), builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) { if (snapshot.hasError) { return Text( 'Error: ${snapshot.error}'); } if (snapshot.connectionState == ConnectionState.waiting) { return const CircularProgressIndicator(); } final List<DocumentSnapshot> orderDocs = snapshot.data!.docs; if (orderDocs.isEmpty) { return const Text( 'no orders yet'); } return ListView.builder( itemCount: orderDocs.length, itemBuilder: (BuildContext context, int index) { final orderData = orderDocs[index].data() as Map<String, dynamic>; final List<dynamic> imageUrl = orderData['imageUrls']; final pname = orderData['pname']; final cname = orderData['cname']; return GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => productdetails( pname: pname, // Add more data variables as needed ), ), ); }, child: SizedBox( height: screenHeight * 0.16, child: Card( color: customColor, child: Stack( children: [ Stack( children: [ Row( children: [ Padding( padding: EdgeInsets.all( screenWidth * 0.01), child: CircleAvatar( radius: screenWidth * 0.03, backgroundImage: NetworkImage( imageUrl.first), ), ), ], ), Padding( padding: EdgeInsets.only( left: screenWidth * 0.08, top: screenHeight * 0.026), child: Column( children: <Widget>[ Row( children: [ Expanded( child: Text( 'Product: $pname sdfsdafdasfdasfdsafsdafdsfsdafdsfdsfsadfasdfasdf', style: GoogleFonts.getFont( 'Outfit', textStyle: TextStyle( fontSize: screenWidth * 0.015, color: Colors.white, ), ), softWrap: false, maxLines: 1, overflow: TextOverflow.ellipsis, ), ), ], ), Row( children: [ Expanded( child: Text( 'By Company: $cname', style: GoogleFonts.getFont( 'Outfit', textStyle: TextStyle( fontSize: screenWidth * 0.01, color: Colors.white, ), ), softWrap: false, maxLines: 1, overflow: TextOverflow.ellipsis, ), ), ], ), ], ), ), ], ), ], ), ), ), ); }, ); }, ), ), ], ), ), ); }, ), ], ), ), ), ], ), ], ), ), ); } } class HexColor extends Color { HexColor(final String hexColor) : super(_getColorFromHex(hexColor)); static int _getColorFromHex(String hexColor) { hexColor = hexColor.toUpperCase().replaceAll("#", ""); if (hexColor.length == 6) { hexColor = "FF$hexColor"; } return int.parse(hexColor, radix: 16); } }
main.dart
import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'firebase_options.dart'; import 'homescreen.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp( options: DefaultFirebaseOptions.web ); runApp(const Eaziprep()); } class Eaziprep extends StatelessWidget { const Eaziprep({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Eazi Prep', home: const homescreen(), routes: { homescreen.home: (context) => const homescreen(), }, ); } }
1. 固定Firestore流的初始化时机
桌面平台下,Firestore流在build方法中重复创建可能导致线程问题,将流的初始化移至initState,确保仅创建一次:
class _homescreenState extends State<homescreen> { late Stream<QuerySnapshot> _ordersStream; @override void initState() { super.initState(); _ordersStream = FirebaseFirestore.instance.collection('orders').snapshots(); } @override Widget build(BuildContext context) { // 保留原有代码,仅将StreamBuilder的stream替换为_ordersStream SizedBox( height: screenHeight * 0.5, child: StreamBuilder<QuerySnapshot>( stream: _ordersStream, builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) { // 原有builder逻辑不变 }, ), ); } }
2. 适配桌面平台的Firebase初始化
当前代码使用了Web平台的配置,桌面应用需对应平台的Firebase配置:
- 运行
flutterfire configure,选择目标桌面平台(Windows/macOS/Linux)生成对应配置 - 修改main.dart中的初始化代码:
await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform );
3. 升级Firebase依赖
cloud_firestore和firebase_core的旧版本可能存在桌面线程问题,升级至最新版本:
- 修改
pubspec.yaml中的依赖版本号 - 运行
flutter pub upgrade更新依赖
4. 延迟初始化流(可选)
若仍存在线程问题,可在页面渲染完成后再初始化流:
@override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { _ordersStream = FirebaseFirestore.instance.collection('orders').snapshots(); setState(() {}); }); }
内容的提问来源于stack exchange,提问作者Muteeb Rehman

