getx icon indicating copy to clipboard operation
getx copied to clipboard

You need to call "Get.put(xx)" or "Get.lazyPut(()=>xx())

Open wen14701083 opened this issue 1 year ago • 9 comments

The following usage scenarios will cause errors。 click B controller not found,You need to call "Get.put(xx)" or "Get.lazyPut(()=>xx())

1.A ---jump ---> B, 2.B --- back --- A ----quickly clicks--> B

A code:

class SplashWidget extends GetView<SplashLogic> {
  SplashWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Splash"),
      ),
      body: InkWell(
        onTap: () {
          Get.toNamed(AppRoutes.home);
        },
        child: Container(
          width: double.infinity,
          height: double.infinity,
          child: const Center(
            child: Text("跳转"),
          ),
        ),
      ),
    );
  }
}

B code:

class MainWidget extends GetView<MainLogic> {
  MainWidget({Key? key}) : super(key: key);

  final logic = Get.find<MainLogic>();

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text("Main"),
      ),
      body: InkWell(
        onTap: () {
          controller.changeContent();
        },
        child: Container(
          width: double.infinity,
          height: double.infinity,
          child: Center(
            child: GetBuilder<MainLogic>(
              assignId: true,
              builder: (logic) {
                return Text(controller.content);
              },
            ),
          ),
        ),
      ),
    );
  }
}

wen14701083 avatar May 28 '24 08:05 wen14701083

Hi! Did you use Bindings when you call Get.toNamed(AppRoutes.home); on screen A? If you use bindings, pass you MainLogic controller in bindings like that

class HomeBindings extends Bindings {
  @override
  void dependencies() {
    Get.put(MainLogic());
  }
}

and pass your Binding in GetPage

or if you don't want use Binding you need to call Get.put before use call Get.find

For example you can init your controller automatically with GetBuilder

class MainWidget extends GetView<MainLogic> {
  const MainWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Main"),
      ),
      body: InkWell(
        onTap: () {
          controller.changeContent();
        },
        child: SizedBox(
          width: double.infinity,
          height: double.infinity,
          child: Center(
            child: GetBuilder<MainLogic>(
              init: MainLogic(), //HERE!!
              assignId: true,
              builder: (logic) {
                return Text(controller.content);
              },
            ),
          ),
        ),
      ),
    );
  }
}

or you can call Get.put in build method before returning you widgets

class MainWidget extends GetView<MainLogic> {
  const MainWidget({super.key});

  @override
  Widget build(BuildContext context) {
    Get.put(MainLogic()); //HERE;

    return Scaffold(
      appBar: AppBar(
        title: const Text("Main"),
      ),
      body: // YOUR UI
    );
  }
}

egortabula avatar May 28 '24 10:05 egortabula

Yes, I used bindings, this is only possible if B quickly jumps to B again when B returns to A, other scenarios are normal.

class SplashBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => SplashLogic());
  }
}

class MainBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => MainLogic());
  }
}

class AppPages {
  static const initial = AppRoutes.initial;

  static final List<GetPage> getPages = [
    GetPage(
      name: AppRoutes.initial,
      page: () => SplashWidget(),
      binding: SplashBinding(),
    ),
    GetPage(
      name: AppRoutes.home,
      page: () => MainWidget(),
      binding: MainBinding(),
    ),
  ];
}

lib.zip

wen14701083 avatar May 29 '24 00:05 wen14701083

Hello! Yes, I also caught an error, but in order to catch it, I need to very quickly press the button and return to screen B before Get has time to call onDispose.

If in your case you are supposed to press so quickly, then two options come to mind.

  1. Just block the button on the screen And if your controller has not yet been removed from memory. For example, when tapping, you can check for dependencies in memory
class SplashWidget extends GetView<SplashLogic> {
  const SplashWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Splash"),
      ),
      body: InkWell(
        onTap: () async {
          try {
            // Try to find your controller
            final mainLogic = Get.find<MainLogic>();

            // If it still in memory, do nothing
            return;
          } catch (e) {
            // If it is not in memory, push your route
            await Get.toNamed(AppRoutes.home);
          }
        },
        child: const SizedBox(
          width: double.infinity,
          height: double.infinity,
          child: Center(
            child: Text("Go home"),
          ),
        ),
      ),
    );
  }
}
  1. There is an option not to delete the controller from memory.
class MainBinding extends Bindings {
  @override
  void dependencies() {
    // Use permament `true` and Get will not remove your dependency from memory.
    Get.put(MainLogic(), permanent: true);
  }
}

egortabula avatar May 29 '24 09:05 egortabula

Um... After B returns to A, onDispose is called about 0.3~0.5s. The first option requires an interception to be added before all page jumps; The second option occupies memory all the time and is not very friendly.

Hope there's a better solution. Such as reducing the latency of onDispose, or not removing onDispose when a new GetView is using controller.

wen14701083 avatar May 29 '24 10:05 wen14701083

Quite a few users are seeing this error in apps that are currently in production. Has this issue been fixed in GetX5?

synstin avatar May 30 '24 04:05 synstin

Quite a few users are seeing this error in apps that are currently in production. Has this issue been fixed in GetX5?

Hello! No, this bug was not fixed in Getx 5.0. But I got the impression that in Get 5.0 I still catch it less often than in v4.6.6

egortabula avatar May 30 '24 05:05 egortabula

Hi, you can try set binding parameter in Get.to(), that error comes when you set binding in bindings file only. And maybe you need to set 'preventDuplicates' to prevent not opening the widget with the same tree

Get.to(
  () => widget,
  preventDuplicates: false,
  binding: BindingsBuilder.put(controller, tag: tag),
);

andrepurnomo avatar May 31 '24 17:05 andrepurnomo

@egortabula

Is it possible to check with isRegistered instead of catching the error with find?

synstin avatar Jun 13 '24 05:06 synstin

I have also encountered this problem. When I quickly enter and exit the page, this error will be caused. I try to modify the code by adding a mixin GetReferenceMixin to GetInstance. As long as GetBuilder is not released, GetxController will not be released.Reference code

lwq1365102044 avatar Jun 21 '24 08:06 lwq1365102044

Any Update?

wds1181977 avatar Nov 29 '24 07:11 wds1181977