LayoutBuilder致GetX实例重启丢数据,如何保留Controller实例?
解决Flutter Web中GetX Controller因屏幕尺寸变化丢失数据的问题
问题核心原因
你当前的代码存在两个关键问题导致Controller实例被意外销毁重建:
- 在
_MainState的成员变量中直接执行Get.put(),若因窗口尺寸变化触发组件树重构(Web端部分场景下可能发生),会重复执行初始化逻辑; - 使用普通
MaterialApp而非GetX提供的GetMaterialApp,无法保障Controller的生命周期与应用全局状态绑定。
具体解决方案
方案一:改用GetMaterialApp并规范Controller初始化
这是最稳妥的方案,利用GetX官方集成的应用组件来管理Controller生命周期:
class _MainState extends State<Main>{ late Controller controller; @override void initState() { super.initState(); // 仅在首次初始化时创建实例,已存在则直接返回已有实例 controller = Get.put(Controller(), permanent: true); } @override Widget build(BuildContext context) { return GetMaterialApp( debugShowCheckedModeBanner: false, home: Container( width: largura_total, height: altura_total, decoration: BoxDecoration( color: Colors.white, image: DecorationImage( image: AssetImage('assets/wallpaper-tela.jpg'), fit: BoxFit.cover ) ), child: LayoutBuilder( builder: (context, constraints){ var largura = constraints.maxWidth; var altura = constraints.maxHeight; var largura_coluna = (largura - 240)/14; if(largura>1400 && altura > 500){ return Scaffold([...]); } else if(largura>1000 && largura<1400 && altura > 500){ return Scaffold([...]); } else if(largura<1000 && largura>350 && altura > 500){ return Scaffold([...]); } else { return Scaffold([...]); } } ), ) ); } }
方案二:用Get.find()复用已存在的Controller实例
如果不想替换MaterialApp,可以通过判断实例是否已注册来避免重复初始化:
class _MainState extends State<Main>{ Controller get controller => Get.find<Controller>(); @override void initState() { super.initState(); // 仅在实例未注册时初始化 if (!Get.isRegistered<Controller>()) { Get.put(Controller(), permanent: true); } } @override Widget build(BuildContext context) { return MaterialApp( // 原有代码保持不变 home: Container( child: LayoutBuilder( builder: (context, constraints){ // 使用controller时直接调用this.controller即可 // 原有布局逻辑不变 } ), ) ); } }
调试排查辅助
如果仍出现Controller销毁的情况,可以在Controller中添加日志确认销毁触发点:
class Controller extends GetxController{ var lista_mostrar = <ItemMostrar>[].obs; @override void onClose() { print("Controller被销毁"); // 控制台输出调试信息 super.onClose(); } }
若打印该日志,说明有代码主动调用了Get.delete<Controller>()或类似销毁方法,需排查业务逻辑中的相关代码。
内容的提问来源于stack exchange,提问作者Roger Walter
相关产品推荐
相关产品推荐

