【问题标题】:GetX Controller not disposing off automaticallyGetX 控制器不自动处理
【发布时间】:2021-11-02 20:12:28
【问题描述】:

我有一个在 Android 上运行的极简主义示例应用程序,仅使用 GetX 作为状态管理库。有两个屏幕 LandingPage 和 MainScreen。从 MainScreen 返回到 LandingPage 屏幕时,控制器未按预期自动处理。 我只使用 Flutter 的 Navigation 而不使用 GetMaterialApp 包装。

我的期望是当控制器被实例化时,控制器暴露的值应该被重置为其初始值。 但是,小部件继续显示来自控制器的最后一个值。

我现在使用的是最新版本的 Flutter 和 GetX:分别是 2.2.3 和 4.3.8

感谢您的帮助。

代码:

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetMaterialApp(
  title: 'Flutter Demo',
  theme: ThemeData(
   
    primarySwatch: Colors.purple,
  ),
  home: LandingScreen(),
  );
 }
} 

class LandingScreen extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
  return Container(
   color: Colors.blue[800],
   child: Center(
     child: ElevatedButton(
       onPressed: () => {
         Get.to(MainScreen())
       },
       child: const Text('Navigate to Second Screen'),
     ),
    ),
  );
 }
}

class MainScreen extends StatelessWidget {
 final MyController controller = Get.put(MyController());

 @override
 Widget build(BuildContext context) {
  return Scaffold(
  body: SafeArea(
    child: Container(
      color: Colors.blueAccent,
      child: Center(
        child: Column(
          children: [
            Obx(() => Text('Clicked ${controller.count}')),
            FloatingActionButton(
              onPressed: controller.increment,
              child: Text('+'),
            ),
            ElevatedButton(
              onPressed: ()=>{Navigator.of(context).pop()},
              child: Text('Go Back'),
            )
          ],
          ),
         ),
        ),
       ),
      );
     }
    }

  class MyController extends GetxController {

   var count = 0.obs;
   void increment() => count++;

  }

【问题讨论】:

  • 是的,除非您使用 GetX 导航,否则控制器不会释放。
  • 好的。我将尝试使用 GetX 导航和更新。文档中的任何地方都提到过它吗?
  • 我尝试了 GetX Navigation 以及使用 GetMaterialApp 进行包装,结果却没有运气:/。有什么建议吗?
  • 我遇到了类似的问题,但在使用 getx 导航后处理工作正常。可以分享代码吗?
  • 好的,所以我知道我必须通过一个回调来返回那个小部件而不是小部件本身。它现在可以与 GetMaterialApp 一起正常工作。

标签: flutter flutter-getx


【解决方案1】:

Get.putMainScreen 的字段移到其build() 方法内。

然后可以在弹出MainScreen 时释放控制器。

现状

控制器不会被释放:

class MainScreen extends StatelessWidget {
 final MyController controller = Get.put(MyController());

 @override
 Widget build(BuildContext context) {
  return Scaffold(

实例化和注册 (Get.put(...)) 不应不作为字段进行

否则,控制器的注册附加到LandingScreen,而不是MainScreen。而MyController 只会在LandingScreen 被处理时才会被处理。由于这是上面代码中的home Widget,因此仅在应用退出时才会进行处理。

修复:将Get.put移动到build()方法。

内部构建()

class MainScreen extends StatelessWidget {

 @override
 Widget build(BuildContext context) {
  // ↓ instantiate/register here inside build ↓
  final MyController controller = Get.put(MyController());
  return Scaffold(

现在当MainScreen 从路由堆栈中弹出时,MyController 将被清理/处置。

这是 Flutter 框架的导航 + Get 的一个怪癖。

请参阅 this issue 获取 Eduardo 的解释/示例,Get 的维护者。

【讨论】:

  • 如果我出于任何原因使用 StatefulWidget 怎么办?将其放入构建中可能不是一个好主意?
  • @Mena 嗯...,乍一看,我想不出为什么将它放入build()build() 方法中会不好的原因@。但是,在StatefulWidget's State 对象中注册控制器可能更有意义。当State 对象被释放时,控制器也会被释放。
【解决方案2】:

您需要先使用 GetX 导航。 但是,在撰写此答案时,有一个 bug 导致控制器不会自动处理掉。因此,现在建议使用绑定或从 StatefulWidget 手动处理它们,直到修复错误。

@override
  void dispose() {
    Get.delete<Controller>();
    super.dispose();
  }

2021 年 11 月 22 日更新 您仍然可以使用上述解决方案,或者对于更优雅的方法,您可以使用Bindings 以及扩展GetView&lt;YourController&gt; 而不是有状态/无状态小部件。 GetXController 将提供 StatefulWidget 所需的大部分功能。您也不必使用 GetX Navigation。

这种方法在使用嵌套导航时也适用。

要使用绑定,有多种方法解释here

【讨论】:

  • 这是一个超级答案,当我们转到另一个屏幕控制器时会关闭,当我们返回时它会重新加载
【解决方案3】:

你可以像下面这样延迟初始化你的控制器:

late final YourController controller;

在你的 initState 函数内部:

@override
void initState() {
    super.initState();

    Get.delete<YourController>();
    controller = Get.put(YourController());
}

这将解决您的问题

【讨论】:

    【解决方案4】:

    如果您在 getMaterialApp 上添加路由,则无需在构建中启动控制器:

    添加 'initialRoute' 和 'getPages' 属性并删除 home 属性:

    class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.purple,
      ),
      initialRoute: '/landing',
      getPages: [
        GetPage(name: '/landing', page: () => LandingScreen()),
        GetPage(name: '/main', page: () => MainScreen()),
      ],
      );
     }
    }
    

    在 LandingPage() 上将 Get.to() 更改为 Get.toNamed():

    class LandingScreen extends StatelessWidget {
     @override
     Widget build(BuildContext context) {
      return Container(
       color: Colors.blue[800],
       child: Center(
         child: ElevatedButton(
           onPressed: () => Get.toNamed('/main'),
           child: const Text('Navigate to Second Screen'),
         ),
        ),
      );
     }
    }
    

    然后在 MainScreen 上将导航器弹出更改为 Get.back():

    class MainScreen extends StatelessWidget {
     final MyController controller = Get.put(MyController());
    
     @override
     Widget build(BuildContext context) {
      return Scaffold(
      body: SafeArea(
        child: Container(
          color: Colors.blueAccent,
          child: Center(
            child: Column(
              children: [
                Obx(() => Text('Clicked ${controller.count}')),
                FloatingActionButton(
                  onPressed: controller.increment,
                  child: Text('+'),
                ),
                ElevatedButton(
                  onPressed: ()=>Get.back(),
                  child: Text('Go Back'),
                )
              ],
              ),
             ),
            ),
           ),
          );
         }
        }
    

    【讨论】:

      猜你喜欢
      • 2023-01-17
      • 2022-01-23
      • 2021-12-11
      • 2021-08-09
      • 2021-07-18
      • 1970-01-01
      • 1970-01-01
      • 2016-01-24
      • 1970-01-01
      相关资源
      最近更新 更多