You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();
  },
)

测试验证

  1. 断网启动应用:应用正常启动,控制台打印连接失败信息,但不会崩溃
  2. 恢复网络:Provider监听到网络变化,自动触发MongoDB重新连接,连接成功后可正常操作数据库
  3. 操作中断网:数据库操作会打印提示但不会崩溃,恢复网络后自动重新连接,可继续操作

这样就彻底解决了断网崩溃的问题,同时保证网络恢复后应用能正常运行。

内容的提问来源于stack exchange,提问作者Abhishek Tiwari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 16:09:10