Flutter中使用GetX Provider构造函数时值设置异常的问题
问题解析与解决方案
核心原因:Get.put()的执行逻辑
你遇到的现象本质是对GetX依赖注入机制的误解,具体拆解:
- 当你调用
Get.put(AppProvider())时,首先会执行AppProvider()构造函数创建一个新实例,所以每次都会触发构造函数里的print(getNumbers.length),输出0; - 接着GetX会检查内部的依赖容器,判断是否已经存在
AppProvider类型的实例:- 第一次跳转时,容器为空,GetX会把刚创建的实例存入容器,后续返回的都是这个实例;
- 第二次跳转时,容器里已经有了之前保存数据的实例,GetX会丢弃刚创建的新实例,直接返回容器中已有的旧实例;
- 你界面上使用的
provider变量是容器里的旧实例,所以能看到之前添加的数字,但构造函数的打印来自被丢弃的新实例,所以显示0。
验证逻辑的方法
在AppProvider里添加实例哈希值打印,就能直观看到新旧实例的区别:
AppProvider() { _numbers = []; print("构造函数执行,实例hashCode: $hashCode,列表长度: ${getNumbers.length}"); } void addNumber(int number) { _numbers.add(number); print("添加数据,当前实例hashCode: $hashCode,列表长度: ${getNumbers.length}"); update(); }
第二次跳转时,你会看到构造函数打印的hashCode和后续操作实例的hashCode完全不同,证明是两个独立对象。
正确写法
方案1:提前全局初始化Provider
在App启动时(比如main函数)初始化一次,后续直接获取已有实例:
void main() { Get.put(AppProvider()); runApp(MyApp()); }
然后在SecondScreen里直接获取:
final provider = Get.find<AppProvider>();
这样构造函数只会执行一次,不会产生多余的实例和打印。
方案2:用Get.find判断是否已存在实例
如果不想提前初始化,可以用Get.find配合Get.put,避免重复创建实例:
final provider = Get.find<AppProvider>() ?? Get.put(AppProvider());
额外优化点
AppProvider里的_numbers已经在成员变量处初始化了[],不需要在构造函数里再次赋值;- SecondScreen不需要用StatefulWidget,借助GetX的响应式能力,用
Obx包裹刷新组件即可,无需手动调用setState():
class SecondScreen extends StatelessWidget { const SecondScreen({Key? key}) : super(key: key); final provider = Get.find<AppProvider>(); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Obx(() => Text(provider.getNumbers.length.toString(), style: const TextStyle(fontSize: 50))), TextButton( onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (_) => const FirstScreen())), child: const Text('Move To First Screen'), ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: () => provider.addNumber(Random().nextInt(1000)), child: const Icon(Icons.add), ), ); } }
内容的提问来源于stack exchange,提问作者user22362195
相关产品推荐
相关产品推荐

