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

Flutter Getx Providers重复初始化问题求助

解决GetX Providers重复初始化问题

问题现象

使用GetX包管理应用状态时,所有Providers被多次初始化,控制台输出重复的实例创建日志,同时出现Firebase后台隔离重复启动警告。

现有代码实现

主入口初始化代码

Future<void> main() async {
  WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
  FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);

  SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
  ErrorWidget.builder = (e) => ErrorScreen(e.exception);

  await App.initializeProviders();
  if (Get.find<AuthProvider>().isAuth) await App.initializeUserProviders();


  runApp(const Appi());
}


class Appi extends StatelessWidget {
  const Appi({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

核心Providers初始化方法

static initializeProviders() async {
    try {
      Get.lazyPut<AuthProvider>(() => AuthProvider(), fenix: true);
      Get.lazyPut<SettingsProvider>(() => SettingsProvider(), fenix: true);
      Get.put<NotificationsProvider>(NotificationsProvider(), permanent: true);
      await Get.find<AuthProvider>().load();
      await Get.find<SettingsProvider>().load();
      await FirebasePlugin.initializeApp();
    } catch (e) {
      print(e);
    }
  }

已认证用户专属Providers初始化方法

static initializeUserProviders() async {
    try {
      Get.lazyPut<MainProvider>(() => MainProvider(), fenix: true);
      Get.lazyPut<FiltersProvider>(() => FiltersProvider(), fenix: true);
      Get.lazyPut<CartProvider>(() => CartProvider(), fenix: true);
      Get.lazyPut<SearchProvider>(() => SearchProvider(), fenix: true);
      // Get.lazyPut(() => HomeProvider(), fenix: true);
      // Get.find<HomeProvider>().load();
      Get.find<NotificationsProvider>().load();
      Get.find<FiltersProvider>().load();
      Get.find<CartProvider>().load();
    } catch (e) {
      //
    }
  }

控制台输出日志

[GETX] Instance "NotificationsProvider" has been created
[GETX] Instance "NotificationsProvider" has been initialized
2[GETX] Instance "AuthProvider" has been created
2[GETX] Instance "AuthProvider" has been initialized
[GETX] Instance "NotificationsProvider" has been created
[GETX] Instance "NotificationsProvider" has been initialized
[GETX] Instance "AuthProvider" has been created
[GETX] Instance "AuthProvider" has been initialized
2[GETX] Instance "SettingsProvider" has been created
2[GETX] Instance "SettingsProvider" has been initialized
[GETX] Instance "SettingsProvider" has been created
[GETX] Instance "SettingsProvider" has been initialized
2
W/FLTFireMsgService( 5927): Attempted to start a duplicate background isolate. Returning...

各Provider的load方法

AuthProvider.load()

Future<void> load() async {
    if (_profile.value != null && _token.value != null) return;
    final localStorage = await SharedPreferences.getInstance();
    final lt1 = localStorage.getString('somekey1');
    final lt2 = localStorage.getString('somekey2');
    final lt3 = localStorage.getString('somekey3');
    final localProfile = localStorage.getString('_up');
    if (lt1 != null && lt2 != null && lt3 != null && localProfile != null) {
      _token.value = lt1 + lt2 + lt3;
      final profile = json.decode(localProfile);
      _profile.value = UserModel.fromJson(profile, avatar: profile['avatar']);
      update();
      return;
    }
  }

FiltersProvider.load()

load() async {
    await App.getData('PRD/filters.php').then((value) {
      if (value != null) {
        final platforms = value["brands"] as Map<String, dynamic>;
        final stores = value["stores"] as Map<String, dynamic>;
        setFilters(stores.values.toList(), platforms.values.toList());
      }
    }).catchError((e) {
      throw e;
      // TODO:: handle error
    });
  }

void setFilters(
    List<dynamic> stores,
    List<dynamic> platforms, {
    bool local = false,
  }) {
    if (stores.isEmpty || platforms.isEmpty) return;
    _allPlatforms.value.clear();
    _allStores.value.clear();
    _allPlatforms.value.add(Filter.getDefault(isPlatform: true));
    _allStores.value.add(Filter.getDefault());
    for (var platform in platforms) {
      _allPlatforms.value.add(Filter.fromJson(platform, isPlatform: true));
    }
    for (var store in stores) {
      _allStores.value.add(Filter.fromJson(store));
    }
    if (!local) {
      SharedPreferences.getInstance().then((prefs) {
        prefs.setString("allPlatforms", jsonEncode(platforms));
        prefs.setString("allStores", jsonEncode(stores));
      });
    }
    update();
  }

NotificationsProvider.load()

Future<void> load() async {
    final result = await _database.getAll();
    if (result.length == _notifications.value.length) return;
    _notifications.value.clear();
    _notifications.value.addAll(result
        .map((e) => NotificationModel.fromJson({
              'id': e['id'],
              'message': e['title'],
              'type': e['type'],
              'type_id': e['type_id'],
              'level': e['level'],
              'is_new': e['is_new'],
            }))
        .toList());

    if (_notifications.value.isNotEmpty) {
      _notifications.value
          .sort((a, b) => int.parse(a.id).compareTo(int.parse(b.id)));
    }
    update();
  }

CartProvider.load()

Future<void> load() async {
    try {
      final items = await database.getAll();
      _cartItems.clear();
      for (var e in items) {
        _cartItems.add(CartItem.fromJson(e));
      }
      update();
    } catch (e) {
      rethrow;
    }
  }

解决方案

1. 检查GetX实例创建逻辑,避免重复注册

在注册Provider前先检查是否已存在实例,避免重复创建;同时用Get.putAsync替代Get.put+手动load,确保实例初始化完成后再存入容器:

// 修改后的核心初始化方法
static initializeProviders() async {
    try {
      if (!Get.isRegistered<AuthProvider>()) {
        Get.lazyPut<AuthProvider>(() => AuthProvider(), fenix: true);
      }
      if (!Get.isRegistered<SettingsProvider>()) {
        Get.lazyPut<SettingsProvider>(() => SettingsProvider(), fenix: true);
      }
      if (!Get.isRegistered<NotificationsProvider>()) {
        await Get.putAsync<NotificationsProvider>(() async {
          final provider = NotificationsProvider();
          await provider.load();
          return provider;
        }, permanent: true);
      }
      await Get.find<AuthProvider>().load();
      await Get.find<SettingsProvider>().load();
      await FirebasePlugin.initializeApp();
    } catch (e) {
      print(e);
    }
  }

2. 解决Firebase后台隔离重复问题

给Firebase初始化添加单例判断,避免重复执行:

// 封装Firebase初始化逻辑
static Future<void> initFirebase() async {
  static bool _initialized = false;
  if (!_initialized) {
    await FirebasePlugin.initializeApp();
    _initialized = true;
  }
}

3. 优化用户专属Provider初始化逻辑

调用Get.find前先检查实例是否已注册,避免懒加载触发重复创建:

// 修改后的用户专属Provider初始化方法
static initializeUserProviders() async {
    try {
      if (!Get.isRegistered<MainProvider>()) {
        Get.lazyPut<MainProvider>(() => MainProvider(), fenix: true);
      }
      if (!Get.isRegistered<FiltersProvider>()) {
        Get.lazyPut<FiltersProvider>(() => FiltersProvider(), fenix: true);
      }
      if (!Get.isRegistered<CartProvider>()) {
        Get.lazyPut<CartProvider>(() => CartProvider(), fenix: true);
      }
      if (!Get.isRegistered<SearchProvider>()) {
        Get.lazyPut<SearchProvider>(() => SearchProvider(), fenix: true);
      }
      
      // 确认实例存在后再调用load
      if (Get.isRegistered<NotificationsProvider>()) {
        await Get.find<NotificationsProvider>().load();
      }
      if (Get.isRegistered<FiltersProvider>()) {
        await Get.find<FiltersProvider>().load();
      }
      if (Get.isRegistered<CartProvider>()) {
        await Get.find<CartProvider>().load();
      }
    } catch (e) {
      print(e);
    }
  }

4. 检查应用启动流程中的重复执行点

在main函数开头添加日志,确认是否被多次执行:

Future<void> main() async {
  print("Main function executed");
  // ... 其他代码
}

关键注意点

  • fenix: true会在实例销毁后重新创建,如果Provider是全局持久的,可考虑去掉该参数或改用permanent: true。
  • 异步操作中避免多次调用Get.find,确保实例初始化完成后再执行后续逻辑。
  • 对比正常运行的另一款应用,检查GetX、Firebase等依赖包的版本是否一致,版本差异可能导致该问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 00:16:14