Flutter应用断网触发MongoDB ConnectionException崩溃问题(要求使用Provider与connectivity_plus解决)
解决Flutter应用断网时MongoDB连接崩溃的问题
首先咱们来拆解问题根源:你的应用在启动时同步强制发起MongoDB连接,且没有对网络异常做捕获处理,一旦断网,db.open()抛出的ConnectionException就会变成未处理异常直接导致崩溃;另外你也没有监听网络状态变化,恢复网络后无法自动重新连接数据库。
下面我会用provider管理全局网络状态,connectivity_plus监听网络变化,结合异常捕获来彻底解决这个问题:
步骤1:添加依赖
先在pubspec.yaml中补充需要的包:
dependencies: flutter: sdk: flutter mongo_dart: ^0.9.0 auto_route: ^7.3.0 # 保留你原有的路由依赖 provider: ^6.0.5 connectivity_plus: ^4.0.1
执行flutter pub get完成依赖安装。
步骤2:创建网络状态Provider
新建providers/network_status_provider.dart文件,用来统一管理和监听网络状态:
import 'package:flutter/foundation.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; class NetworkStatusProvider extends ChangeNotifier { final Connectivity _connectivity = Connectivity(); bool _isConnected = true; bool get isConnected => _isConnected; NetworkStatusProvider() { // 初始化时检查一次网络状态 _initConnectivity(); // 监听网络状态变化 _connectivity.onConnectivityChanged.listen(_updateConnectionStatus); } Future<void> _initConnectivity() async { final result = await _connectivity.checkConnectivity(); _updateConnectionStatus(result); } void _updateConnectionStatus(ConnectivityResult result) { final wasConnected = _isConnected; _isConnected = result != ConnectivityResult.none; // 仅当网络状态变化时通知监听者,避免不必要的重建 if (wasConnected != _isConnected) { notifyListeners(); } } }
步骤3:修改MongoDB连接逻辑
更新mongoDbFunctions.dart,添加异常捕获、支持重新连接,并且在数据库操作前检查连接状态:
import 'dart:developer'; import 'package:flutter/rendering.dart'; import 'package:mongo_dart/mongo_dart.dart'; import 'package:badone/mongodb_connection/mongoDbModel.dart'; import 'package:badone/mongodb_connection/constant.dart'; class MongoDatabase { static var db, userCollection, reviewCollection; static bool _isDbConnected = false; static bool get isDbConnected => _isDbConnected; // 带异常捕获的连接方法 static Future<void> connect() async { try { if (_isDbConnected) return; // 避免重复发起连接 db = await Db.create(MONGO_CONN_URL); await db.open(); inspect(db); userCollection = db.collection(USER_COLLECTION); reviewCollection = db.collection(REVIEW_COLLECTION); _isDbConnected = true; print("MongoDB连接成功"); } on ConnectionException catch (e) { _isDbConnected = false; print("MongoDB连接失败: ${e.message}"); } catch (e) { _isDbConnected = false; print("连接出错: ${e.toString()}"); } } // 重新连接方法(用于网络恢复后) static Future<void> reconnect() async { if (_isDbConnected) { await db.close(); _isDbConnected = false; } await connect(); } // 所有数据库操作前先检查连接状态 static Future<List<Map<String, dynamic>>> getData() async { if (!_isDbConnected) { print("数据库未连接,无法获取数据"); return []; } return userCollection.find().toList(); } static delete(MongoDbModel data) async { if (!_isDbConnected) { print("数据库未连接,无法删除数据"); return; } try { print("${data.id}"); await userCollection.deleteOne({"id": data.id}); print('deleted done'); } catch (e) { print(e.toString()); } } static Future<void> insert(MongoDbModel data, ModelForData data2) async { if (!_isDbConnected) { print("数据库未连接,无法插入数据"); return; } try { userCollection.insertOne(data.toJson()); reviewCollection.insertOne(data2.toJson()); } catch (e) { print(e.toString()); } } static Future<void> Update(String x, MongoDbModel data) async { if (!_isDbConnected) { print("数据库未连接,无法更新数据"); return; } print(x); userCollection.updateOne( where.eq('id', x), modify.set('name', data.brandCompanyName)); userCollection.updateOne( where.eq('id', x), modify.set('subject', data.productName)); userCollection.updateOne( where.eq('id', x), modify.set('Grade', data.review)); } }
步骤4:更新main.dart,集成Provider
修改main.dart,不再在启动时强制await数据库连接,而是通过Provider管理网络状态:
import 'package:badone/MyApp.dart'; import 'package:badone/providers/network_status_provider.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); runApp( MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => NetworkStatusProvider()), ], child: const MyApp(), ), ); }
步骤5:在MyApp中处理网络状态与数据库连接
更新MyApp.dart,添加网络状态监听,当网络恢复时自动重新连接MongoDB:
import 'package:badone/router/auto_route.gr.dart'; import 'package:badone/mongodb_connection/mongoDbFunctions.dart'; import 'package:badone/providers/network_status_provider.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class MyApp extends StatefulWidget { const MyApp({Key? key}) : super(key: key); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { final _appRouter = AppRouter(); @override void initState() { super.initState(); _setupNetworkListener(); // 初始化时尝试连接数据库 _tryConnectToMongo(); } void _setupNetworkListener() { Provider.of<NetworkStatusProvider>(context, listen: false) .addListener(_onNetworkStatusChanged); } void _onNetworkStatusChanged() { final networkStatus = Provider.of<NetworkStatusProvider>(context, listen: false); if (networkStatus.isConnected) { // 网络恢复时自动重新连接数据库 MongoDatabase.reconnect(); } } void _tryConnectToMongo() async { final networkStatus = Provider.of<NetworkStatusProvider>(context, listen: false); if (networkStatus.isConnected) { await MongoDatabase.connect(); } } @override void dispose() { Provider.of<NetworkStatusProvider>(context, listen: false) .removeListener(_onNetworkStatusChanged); super.dispose(); } @override Widget build(BuildContext context) { return MaterialApp.router( debugShowCheckedModeBanner: false, title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), routerDelegate: _appRouter.delegate(), routeInformationParser: _appRouter.defaultRouteParser(), ); } }
步骤6:添加用户友好提示(可选)
在需要数据库操作的页面,你可以通过Consumer读取网络和数据库状态,给用户直观提示:
Consumer<NetworkStatusProvider>( builder: (context, networkProvider, child) { if (!networkProvider.isConnected) { return const Center(child: Text("当前无网络,请检查连接")); } if (!MongoDatabase.isDbConnected) { return const Center(child: Text("正在连接数据库...")); } // 正常渲染页面内容 return YourPageContent(); }, )
测试验证
- 断网启动应用:应用正常启动,控制台打印连接失败信息,但不会崩溃
- 恢复网络:Provider监听到网络变化,自动触发MongoDB重新连接,连接成功后可正常操作数据库
- 操作中断网:数据库操作会打印提示但不会崩溃,恢复网络后自动重新连接,可继续操作
这样就彻底解决了断网崩溃的问题,同时保证网络恢复后应用能正常运行。
内容的提问来源于stack exchange,提问作者Abhishek Tiwari
相关产品推荐
相关产品推荐

