jonataslaw / getx

Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with Get.
MIT License
10.27k stars 1.61k forks source link

A TextEditingController was used after being disposed. #1671

Closed aboda1986 closed 3 years ago

aboda1986 commented 3 years ago

After dispose TextEditingController in onClose controller method and use Get.offNamed, an error showing in console "A TextEditingController was used after being disposed."

Get version : 4.2.4 Flutter Version: 2.2.3

example:

 @override
  void onClose() {
    userNameController.dispose();
  }

void goToHome()
{
 Get.offNamed(Routes.HOME);
}
HaijunWei commented 3 years ago

I also encountered this problem. 4.1.4 is normal.

binglingziyu commented 3 years ago

@jonataslaw Get version : 4.2.4

LoginPage: Get.offNamed(Routes.main); is not OK. :x:

[GETX] REPLACE ROUTE /login
[GETX] NEW ROUTE /main
[GETX] "LoginPageControllerLoginPage-de1114a0-884e-4703-b496-0d0d88f19209" onDelete() called
[GETX] Instance "LoginPageControllerLoginPage-de1114a0-884e-4703-b496-0d0d88f19209" was restarted.

======== Exception caught by widgets library =======================================================
The following assertion was thrown while finalizing the widget tree:
A TextEditingController was used after being disposed.

Once you have called dispose() on a TextEditingController, it can no longer be used.
When the exception was thrown, this was the stack: 
#0      ChangeNotifier._debugAssertNotDisposed.<anonymous closure> (package:flutter/src/foundation/change_notifier.dart:117:9)
#1      ChangeNotifier._debugAssertNotDisposed (package:flutter/src/foundation/change_notifier.dart:123:6)
#2      ChangeNotifier.removeListener (package:flutter/src/foundation/change_notifier.dart:195:12)
#3      EditableTextState.dispose (package:flutter/src/widgets/editable_text.dart:1675:23)
#4      StatefulElement.unmount (package:flutter/src/widgets/framework.dart:4800:11)
...
====================================================================================================

LoginPage: Get.offAndToNamed(Routes.main); is OK. :white_check_mark:

[GETX] CLOSE TO ROUTE /login
[GETX] GOING TO ROUTE /main
[GETX] "LoginPageControllerLoginPage-49bee134-2b89-4134-b78f-9550d1fce5a2" onDelete() called
[GETX] "LoginPageControllerLoginPage-49bee134-2b89-4134-b78f-9550d1fce5a2" deleted from memory
[GETX] Instance "LoginPageControllerLoginPage-49bee134-2b89-4134-b78f-9550d1fce5a2" already removed.
KevinZhang19870314 commented 3 years ago

@aboda1986 Please paste your minimal repro example but not code snippets.

Also to make sure you are not define controller with static keyword. See https://stackoverflow.com/a/60557145/3322318

aboda1986 commented 3 years ago

Login Controller:

import 'package:Benamart/app/components/alert/one_button.dart';
import 'package:Benamart/app/components/snackbar.dart';
import 'package:Benamart/app/modules/login/models/login.model.dart';
import 'package:Benamart/app/modules/login/providers/login.provider.dart';
import 'package:Benamart/app/modules/register/models/register.model.dart';
import 'package:Benamart/app/routes/app_pages.dart';
import 'package:Benamart/config.dart';
import 'package:Benamart/generated/locales.g.dart';
import 'package:device_info/device_info.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:get_storage/get_storage.dart';

class LoginController extends GetxController {
  final userNameController = TextEditingController();
  final passwordController = TextEditingController();

  RxBool isLoading = false.obs;

  @override
  void onClose() {
    userNameController.dispose();
    passwordController.dispose();
  }

  Future<void> login() async {
    //hide keyboard
    FocusManager.instance.primaryFocus?.unfocus();

    if (userNameController.text.isEmpty) {
      alertOneButton(
              LocaleKeys.messages_fields_required.tr,
              LocaleKeys.login_error_1.tr,
              Config.getAlertStyle(CustomColors.green))
          .show();

      return;
    }

    if (passwordController.text.isEmpty) {
      alertOneButton(
              LocaleKeys.messages_fields_required.tr,
              LocaleKeys.login_error_2.tr,
              Config.getAlertStyle(CustomColors.green))
          .show();

      return;
    }

    final deviceInfoPlugin = DeviceInfoPlugin();
    String uID = "";

    try {
      if (GetPlatform.isAndroid) {
        final build = await deviceInfoPlugin.androidInfo;
        uID = build.androidId;
      } else if (GetPlatform.isIOS) {
        final data = await deviceInfoPlugin.iosInfo;
        uID = data.identifierForVendor;
      }
    } on PlatformException {}

    final loginModel = LoginModel(
      userName: userNameController.text,
      password: passwordController.text,
      uID: uID,
      device: GetPlatform.isAndroid ? 'Android' : 'IOS',
    );

    isLoading.value = true;

    final loginProvider = Get.find<LoginProvider>();

    final response = await loginProvider.login(loginModel);

    isLoading.value = false;

    if (response.status.hasError) {
      if (response.statusCode == null) {
        showSnackBar(LocaleKeys.messages_error.tr,
            LocaleKeys.messages_no_internet.tr, CustomColors.red);
      } else {
        showSnackBar(LocaleKeys.messages_error.tr, response.statusText!,
            CustomColors.red);
      }

      return;
    }

    final jsonResult = registerResponseModelFromJson(response.bodyString!);

    if (jsonResult.error == 1) {
      showSnackBar(LocaleKeys.messages_error.tr, LocaleKeys.login_error_3.tr,
          CustomColors.red);

      return;
    }

    final clientDetails = jsonResult.clientDetails;

    //navigate to home screen

    final storage = GetStorage();

    await storage.write('IsClientLogin', true);

    await storage.write('ClientDetails', clientDetails!.toJson());

    Get.offNamed(Routes.HOME);
  }
}

@KevinZhang19870314 After call login method in LoginController, and navigate to Routes.HOME, issue happened.

if you use offAndToNamed its okay, no issue

KevinZhang19870314 commented 3 years ago

Try to call super.onClose(); at the end of your LoginController onClose method.

aboda1986 commented 3 years ago

@KevinZhang19870314 unfortunality, still same issue happening after adding super.onClose(); in onClose method

jonataslaw commented 3 years ago

Please provide a replay code (no additional packages) for the issue to be investigated

aboda1986 commented 3 years ago

@jonataslaw here is a very simple project

https://github.com/aboda1986/textconteroller_issue

jonataslaw commented 3 years ago

Fixed on lastest version