getx
getx copied to clipboard
You need to call "Get.put(xx)" or "Get.lazyPut(()=>xx())
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);
},
),
),
),
),
);
}
}
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
);
}
}
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(),
),
];
}
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.
- 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"),
),
),
),
);
}
}
- 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);
}
}
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.
Quite a few users are seeing this error in apps that are currently in production. Has this issue been fixed in GetX5?
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
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),
);
@egortabula
Is it possible to check with isRegistered instead of catching the error with find?
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
Any Update?