Search code examples
flutterflutter-getx

Flutter GetX Controller Not Getting Disposed Automatically


I'm Using GetX As A State Management Tool and it was very helpful, but I got a bug when navigating to a page and going back the page controller doesn't get disposed and the onClose() method doesn't get called so I can't dispose the controller manually using Get.delete<Controller>(). and I checked answers here pointing out to initialize the controller in the build() method and it also didn't work.

I'm using GetX ^4.6.5

Navigating with Named Navigation i.e Get.toNamed('/page1 )

UPDATE

code snippet the Page

class UnitsList extends StatelessWidget {

  const UnitsList({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    const horizontalPadding = EdgeInsets.symmetric(horizontal: 10);
    final UnitsListController controller = Get.put(UnitsListController());

    return Scaffold(
      appBar: AppBar(
        title: Text('Units List'),
        centerTitle: true,
      ),
      body: Padding(
        padding: horizontalPadding,
        child:GetX<UnitsListController>(
          builder: (_)=>controller.isBusy.value
              ?const AppCircularIndicator()
              : SingleChildScrollView(
              child: Column(
                children: [
                  GetBuilder<UnitsListController>(
                    builder:(_)=> ListView.builder(
                      shrinkWrap: true,
                      physics: const NeverScrollableScrollPhysics(),
                      itemCount: controller.unitsList.length,
                      itemBuilder: (context, index) {
                        var item = controller.unitsList[index];                    
                        return GestureDetector(
                          onTap: () {
                            controller.selectedUnit = item;
                            print('${controller.selectedUnit!.rent}');
                            controller.onUnitTap();
                          },
                          child:  AppUnitCard(
                           //...
                          ),
                        );
                      },
                    ),
                  ),
                ],
              )
          ),
        )

      ),
    );
  }
}

And the Controller

class UnitsListController extends GetxController {
  final _className = 'Units List Controller';

  List<Unit> unitsList = [];

  String? _requestType;

  RxBool isBusy = false.obs;
  Unit? selectedUnit;

  @override
  void onInit() async {
    log('onInit', name: _className);

    isBusy.value = true;

    //Some APIs Calls and handling data
    super.onInit();
  }

  @override
  void onReady() {
    isBusy.value = false;
    log('onReady', name: _className);
    super.onReady();
  }

  @override
  void onClose() {
    log('onClose', name: _className);
    super.onClose();
  }

  void onUnitTap() {
    log('_requestType : $_requestType', name: _className);
    if(selectedUnit == null ||_requestType==null){
      return;
    }
    

      var selectedUnitData = {NavigationParams.unit: selectedUnit!.toJson()};
    
      if (_requestType == NotificationsStrings.evacuation) {
        Get.toNamed(AppRoutes.evacuationRequestPage,
            arguments: selectedUnitData);
      } else if (_requestType == NotificationsStrings.maintenance) {
        Get.toNamed(AppRoutes.maintenanceRequestPage,
            arguments: selectedUnitData);
      } else if (_requestType == NotificationsStrings.renting) {
        Get.toNamed(AppRoutes.paymentServicesList, arguments: selectedUnitData);
      } else if (_requestType == NavigationParams.searchUnitTapRequest) {
        Get.toNamed(AppRoutes.unitDetailsPage,
            arguments: selectedUnitData,
            parameters: {
              NavigationParams.unitDetailsKey: NavigationParams.unitDetailsRent
            });
      }
      else if (_requestType == NavigationParams.customerViewUnitTapRequest) {
        Get.toNamed(AppRoutes.unitDetailsPage,
            arguments: selectedUnitData,
            );
      }
      else if (_requestType == NavigationParams.ownerInvitingSpUnitTapRequest) {
        Get.toNamed(AppRoutes.servicesProvidersList,
            arguments: selectedUnitData);
      }
      else if (_requestType == NavigationParams.ownerViewUnitTapRequest ||
          _requestType == NavigationParams.ownerViewEmptyUnitTapRequest ||
          _requestType == NavigationParams.ownerViewOccupiedUnitTapRequest) {
        Get.toNamed(AppRoutes.unitDetailsPage,
            arguments: selectedUnitData,
            parameters: {
              NavigationParams.unitDetailsKey: NavigationParams.unitDetailsEdit
            });
      }  
  }  
}

so please any help would be appreciated


Solution

  • So I've solved my problem with a work around approach, so don't judge me if that's not a best practice or a poor solution.

    lets consider that i have a two pages Page1(),Page2() and their controllers Page1Controller(),Page2Controller(). and i wanted to go back and forth and when i revisit Page2() i wanted it's controller to be re-Initialized.

    so what i did simply is when i'm at Page1() and before i call Get.to(Page2()) i make sure that the Page2Controller() is already deleted so i use Get.delete<Page2Controller>(); and to test this you can see the loge Page2Controller() onInit().

    so the full solution code is like that:

    Page1Controller Navigation:

    Get.delete<Page2Controller>();
     Get.to(Page2());
    

    and Page2Controller :

    import 'dart:developer';
    
    class Page2Controller extends GetxController {
    final _className='Page 2 Controller';
    
     @override
      void onInit() async{
    log('onInit',name:_className);
    }
    }
    

    you will find out that with this approach the Page2Controller will get Re-Initialized every time you go to Page2