#flutter #oop #dart #flutter-getx
Вопрос:
Это проблема, связанная с getx в flutter. У меня есть 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.
Теперь я хочу получить это значение в 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();
}
}
Ответ №1:
Обзор
На ум приходит пара решений:
- передайте
expiringContracts
список в качестве аргумента конструктораNotificationsController
, если вам нужно сделать это только один раз при создании экземпляра, или - используйте работника getX для обновления
NotificationsController
при каждомexpiringContracts
обновлении
Первое решение не связано с getX, скорее это просто асинхронная координация между ContractsController
и NotificationsController
, поэтому давайте сосредоточимся на 2-м решении: работники getX.
Подробные сведения
В NotificationsController
, создайте метод, который будет получать expiringContracts
.
Что-то вроде:
class NotificationsController extends GetxController {
void refreshContracts(List<ExpiringContract> contracts) {
// do something
}
}
Пожалуйста, обратите внимание: ни один из этих кодов не тестируется. Я пишу это исключительно в StackOverflow, поэтому рассмотрите этот псевдокод.
В ContractsController
мы предоставим приведенный выше метод обратного вызова в качестве конструктора arg:
В 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
}
}
Здесь ever
работник getX принимает наблюдаемое в качестве первого аргумента, а функцию в качестве 2-го аргумента. Эта функция должна принимать аргумент типа, соответствующего наблюдаемой переменной , т. е. List<ExpiringContract>
, следовательно, Тип refreshContractsCallback
был определен как Function(List<ExpiringContract>)
.
Теперь всякий раз , когда наблюдаемое expiringContracts
обновляется ContractsController
, refreshContractsCallback(contracts)
будет вызываться, который предоставляет список истекающих контрактов в NotificationsController
via refreshContracts
.
Наконец, при создании экземпляров двух контроллеров внутри build()
метода вашего маршрута/страницы:
NotificationsController nx = Get.put(NotificationsController());
ContractsController cx = Get.put(ContractsController(nx.refreshContracts));
Хронология событий
NotificationsController
создается какnx
.nx.onInit()
работает, медленный вызовrefreshContracts()
стартовContractsController
создается сnx.refreshContracts
обратным вызовом- ваша страница рисует
nx
на данный момент у вас нет данных о контрактах, так что вы, вероятно, будете. нужен aFutureBuilder
илиObx
/GetX
StatelessWidget
, который восстановится, когда данные в конечном итоге поступят
- когда
refreshContracts()
заканчивается,ever
работник запускается, отправляя контракты наnx
nx.refreshContracts(contracts)
бежит, что-то делает с контрактами
Примечания
- асинхронное/ожидание было удалено из
nx.onInit
ever
работник будет работать, когдаrefreshContract
закончит
Комментарии:
1. Привет. @Бейкер. Спасибо за ваш любезный ответ. Такой подход является замечательным. Спасибо. Это так полезно. В любом случае, я решаю эту проблему другим способом. Я опубликую свой ответ здесь, так что у вас есть немного времени, чтобы проверить это?
Ответ №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.
Спасибо.
Комментарии:
1. Привет @Денис, если это сработает для тебя, отлично. Одна вещь, которую нужно проверить:
ContractsController
удаляется ли она из памяти, когда вы покидаете/открываете вызывающую страницуgetExpiringContracts()
? (Если это так, вы увидите сообщение «ContractsController удален из памяти» в консоли отладки или запуска.) Я спрашиваю , так как контроллер регистрируется внутриContractsController
, что является техникой/идиомой, которую я раньше не видел.2. Привет. @Бейкер. Да, я только что проверил это в своем приложении. Поскольку представление уведомлений будет перенаправляться из представления контракта, это работает хорошо, и нет сообщения о том, что contractsController был удален. Но когда я выхожу из представления уведомлений, оно показывает удаленное сообщение контроллера. Теперь я понимаю, что Get.put и find доступны в одном и том же маршруте стека. Спасибо за ваш любезный ответ.