GetX Controller not disposing off automatically

Aka*_*rai 11 flutter flutter-getx

I have a minimlaist sample app running on Android with GetX as State Management lib only. There are two screens LandingPage and MainScreen. On going back from MainScreen to LandingPage screen, the controller is not autodisposing as expected. I am using Flutter's Navigation only without wrapping with 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++;

  }
Run Code Online (Sandbox Code Playgroud)

Bak*_*ker 15

自动处置

\n

要在删除小部件时释放 GetxController,请在方法内部使用Get.put build(),而不是作为字段。根据 GetX 维护者的说法,这是正确的用法。

\n

然后控制器可以在MainScreen弹出时被丢弃。

\n

错误使用

\n

控制器不会被处置:

\n
class MainScreen extends StatelessWidget {\n final MyController controller = Get.put(MyController());\n\n @override\n Widget build(BuildContext context) {\n  return Scaffold(\n
Run Code Online (Sandbox Code Playgroud)\n

实例化和注册( Get.put(...)) 不应作为字段来完成

\n

否则,控制器的注册将附加到上面的小部件(即LandingScreen在问题的示例中),而不是MainScreen. 并且只有在被处置MyController时才会被处置。LandingScreen(问题的代码中LandingScreen是“home”小部件,它的处理仅在应用程序退出时发生。)

\n

为什么?

\n

如果将控制器实例化为字段,GetX 将使用当前可用的上下文(窗口小部件的上下文,而不是实例化窗口小部件的上下文)来记录该控制器的创建。实例化小部件上下文在其方法之前不可用build()。小部件类的实例化和其方法的运行build()是两个不同的事情。该build()方法不是widget 本身的工厂构造函数,而是 Flutter 框架在widget 实例化后使用的生命周期方法,用于膨胀 widget 并将其插入/挂载为Element使用的生命周期方法,用于膨胀 widget 并将其作为渲染对象的元素树插入/挂载。(这是我目前的理解。)

\n

在问题的示例中,MainScreen小部件是在 的上下文中实例化的LandingScreenMainScreen及其字段在 的上下文中LandingScreen。 方法在实例化 MainScreen\'s build()运行。在其方法运行时可用,但在 Widget 实例化期间不可用。MainScreen\'s contextbuild()

\n

为了在释放MyController时被删除/释放,我们必须在上下文内部实例化,该上下文在调用其方法期间可用。如果我们希望在当前/实例化小部件从小部件树中删除时由 GetX 自动处理它,那么这就是我们应该将 GetxController 与其关联的上下文。MainScreenMyControllerMainScreenbuild(BuildContext context)

\n

正确使用

\n
class MainScreen extends StatelessWidget {\n\n @override\n Widget build(BuildContext context) {\n  // \xe2\x86\x93 instantiate/register here inside build \xe2\x86\x93\n  final MyController controller = Get.put(MyController());\n  return Scaffold(\n
Run Code Online (Sandbox Code Playgroud)\n

现在,当MainScreen从路由堆栈中弹出时,MyController将由 GetX 清理/处置(我假设它会观察路由历史记录以了解何时进行清理)。

\n


Men*_*ena 14

您需要先使用 GetX 导航。然而,在撰写此答案时,存在一个错误导致控制器无法自动处理。因此,现在建议使用绑定或从 StatefulWidget 手动处置它们,直到错误得到修复。

@override
  void dispose() {
    Get.delete<Controller>();
    super.dispose();
  }
Run Code Online (Sandbox Code Playgroud)

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

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

要使用 Bindings,这里解释了多种方法。


Moh*_* PK 6

您可以像下面这样稍后初始化控制器:

late final YourController controller;
Run Code Online (Sandbox Code Playgroud)

在你的 initState 函数中:

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

    Get.delete<YourController>();
    controller = Get.put(YourController());
}
Run Code Online (Sandbox Code Playgroud)

这将解决你的问题