【问题标题】:how can I get the other controller's variable inside one controller in flutter using getx如何使用getx在一个控制器中获取另一个控制器的变量
【发布时间】:2021-11-02 21:37:44
【问题描述】:

这是flutter中getx相关的问题。 我有 2 个控制器。合同控制器和通知控制器。 在 ContractsController 中,我通过调用 Api 请求将值放入观察者变量中。 我现在想要的是在另一个控制器 - NotificationController 中获取该变量的数据。 如何使用 getx 函数获取该值?

合同控制器

class ContractsController extends GetxController {
  ExpiringContractRepository _expiringContractRepository;

  final expiringContracts = <ExpiringContract>[].obs; // This is the value what I want in another controller

  ContractsController() {
    _expiringContractRepository = new ExpiringContractRepository();
  }

  @override
  Future<void> onInit() async {
    await refreshContracts();
    super.onInit();
  }

  Future refreshContracts({bool showMessage}) async {
    await getExpiringContracts();
    if (showMessage == true) {
      Get.showSnackbar(Ui.SuccessSnackBar(message: "List of expiring contracts refreshed successfully".tr));
    }
  }

  Future getExpiringContracts() async {
    try {
      expiringContracts.value = await _expiringContractRepository.getAll(); // put the value from the api
    } catch (e) {
      Get.showSnackbar(Ui.ErrorSnackBar(message: e.toString()));
    }
  }
}

在 api 请求之后,expiringContracts 已成功更新数据。 现在,我想在 NotificationController 中获取该值

通知控制器

class NotificationsController extends GetxController {
  final notifications = <Notification>[].obs;
  ContractsController contractsController;

  NotificationsController() {
  }

  @override
  void onInit() async {
    contractsController = Get.find<ContractsController>();
    print(contractsController.expiringContracts);  // This shows an empty list ?????  
    super.onInit();
  }

}

【问题讨论】:

    标签: flutter oop dart flutter-getx


    【解决方案1】:

    概述

    想到几个解决方案:

    • 如果您只需要在实例化时完成一次,则将 expiringContracts 列表作为构造函数参数传递给 NotificationsController,或者
    • 每次更新 expiringContracts 时,使用 GetX 工作者更新 NotificationsController

    第一个解决方案与 GetX 无关,它只是 ContractsControllerNotificationsController 之间的异步协调,所以让我们关注第二个解决方案:GetX Workers。

    详情

    NotificationsController 中,创建一个将接收expiringContracts 的方法。

    类似:

    class NotificationsController extends GetxController {
    
      void refreshContracts(List<ExpiringContract> contracts) {
        // do something
      }
    
    }
    

    请注意:此代码均未经过测试。我纯粹是在 StackOverflow 中编写的,所以请考虑这个伪代码。

    ContractsController 中,我们将提供上述回调方法作为构造函数参数:

    ContractsController 中,类似:

    class ContractsController {
    
      final expiringContracts = <ExpiringContract>[].obs
    
      final Function(List<ExpiringContract>) refreshContractsCallback;
    
      ContractsController(this.refreshContractsCallback);
    
      @override
      void onInit() {
        super.onInit();
        refreshContracts();  // do your stuff after super.onInit
        ever(expiringContracts, refreshContractsCallback);
        // ↑ contracts → refreshContractsCallback(contracts)
        // when expiringContracts updates, run callback with them
      }
    }
    

    这里 GetX ever worker 将 observable 作为第一个参数,将一个函数作为第二个参数。该函数必须采用与观察到的变量匹配的类型参数,即List&lt;ExpiringContract&gt;,因此refreshContractsCallback 的类型定义为Function(List&lt;ExpiringContract&gt;)

    现在,每当ContractsController 中的可观察expiringContracts 更新时,refreshContractsCallback(contracts) 就会被调用,它通过refreshContracts 将到期合约列表提供给NotificationsController

    最后,在实例化两个控制器时inside the build() method of your route/page

    NotificationsController nx = Get.put(NotificationsController());
    ContractsController cx = Get.put(ContractsController(nx.refreshContracts));
    

    事件时间表

    • NotificationsController 被创建为 nx
    • nx.onInit() 运行,refreshContracts() 的缓慢调用开始
    • ContractsController 被创建,带有 nx.refreshContracts 回调
    • 您的页面绘制
      • nx 目前没有合约数据,所以你会进行调查。需要 FutureBuilderObx/ GetX + StatelessWidget 在数据最终到达时重建
    • refreshContracts() 完成时,ever 工人运行,将合同发送到nx
    • nx.refreshContracts(contracts) 正在运行,正在处理合约

    备注

    • async/await 已从 nx.onInit 中删除
    • ever worker 将在 refreshContract 完成时运行

    【讨论】:

    • 嗨。 @贝克。感谢您的友好回答。这种方法很棒。谢谢。这很有帮助。无论如何,我以另一种方式解决了这个问题。我将在此处发布我的答案,您有时间检查一下吗?
    【解决方案2】:

    GetX 中有一些强大的方法。我用 Get.put 和 Get.find 解决了这个问题

    这是我添加的代码。

    合同控制器

    class ContractsController extends GetxController {
      ExpiringContractRepository _expiringContractRepository;
    
      final expiringContracts = <ExpiringContract>[].obs; // This is the value what I want in another controller
    
      ContractsController() {
        _expiringContractRepository = new ExpiringContractRepository();
      }
    
      @override
      Future<void> onInit() async {
        await refreshContracts();
        super.onInit();
      }
    
      Future refreshContracts({bool showMessage}) async {
        await getExpiringContracts();
        if (showMessage == true) {
          Get.showSnackbar(Ui.SuccessSnackBar(message: "List of expiring contracts refreshed successfully".tr));
        }
      }
    
      Future getExpiringContracts() async {
        try {
          expiringContracts.value = await _expiringContractRepository.getAll(); // put the value from the API
          // ******************************** //
          Get.put(ContractsController()); // Added here
        } catch (e) {
          Get.showSnackbar(Ui.ErrorSnackBar(message: e.toString()));
        }
      }
    }
    

    通知控制器

    class NotificationsController extends GetxController {
      final notifications = <Notification>[].obs;
      ContractsController contractsController;
    
      NotificationsController() {
      }
    
      @override
      void onInit() async {
        // ******************************** //
        contractsController = Get.find<ContractsController>(); // Added here.
        print(contractsController.expiringContracts);  // This shows the updated value
        super.onInit();
      }
    }
    

    最后,我发现 GetX 对于 Flutter 中的状态管理来说虽然简单但功能强大。 谢谢。

    【讨论】:

    • 嗨@Denis,如果这对你有用,那就太好了。要检查的一件事:当您离开/弹出调用getExpiringContracts() 的页面时,ContractsController 是否会从内存中删除自己? (如果是这样,您将在调试或运行控制台中看到“ContractsController 从内存中删除”消息。)我问,因为控制器是在 ContractsController 中注册的,这是我以前从未见过的技术/习语。跨度>
    • 嗨。 @贝克。是的,我刚刚在我的应用程序上进行了检查。由于通知视图将从合同视图路由,因此运行良好,并且没有消息表明contractsController 已被删除。但是当我离开通知视图时,它会显示控制器已删除的消息。现在,我知道 Get.put 和 find 在同一堆栈路由中可用。感谢您的友好回答。
    猜你喜欢
    • 2022-01-23
    • 2021-08-09
    • 1970-01-01
    • 2013-05-21
    • 1970-01-01
    • 2017-03-23
    • 1970-01-01
    • 1970-01-01
    • 2020-11-23
    相关资源
    最近更新 更多