why the Controller instances not destory after call function `onClose()`
Describe the bug
why the Controller instances not destory after call function onClose(). Or am I using the wrong posture?
**Reproduction code example:
import 'dart:async';
import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:pin_code_fields/pin_code_fields.dart';
import 'package:toocans/common/routes/route_manager.dart';
import 'package:toocans/common/utils/app_colors.dart';
import 'package:toocans/common/widgets/design/app_bar/design_app_bar.dart';
import 'package:toocans/common/widgets/design/button/design_button_match_width.dart';
import 'package:toocans/gen/lang_key.dart';
class FAGoogleCreateLogic extends GetxController {
// QR码数据和密钥,实际应用中应从API获取
final qrData = 'https://toocans.example.com/auth?code=123456789012345'.obs;
final secretKey = '123123123123'.obs;
// 验证码输入控制器
late TextEditingController textEditingController;
late StreamController<ErrorAnimationType> errorController;
@override
void onInit() {
super.onInit();
print('==========> FAGoogleCreateLogic onInit: ${identityHashCode(this)}');
textEditingController = TextEditingController();
errorController = StreamController<ErrorAnimationType>();
}
// 复制密钥到剪贴板
void copySecretKey() {
Clipboard.setData(ClipboardData(text: secretKey.value));
Get.snackbar(
LangKey.common.confirm.tr,
LangKey.common.copySuccess.tr,
backgroundColor: AppColors.toastBg,
colorText: AppColors.textWhite,
snackPosition: SnackPosition.BOTTOM,
);
}
// 刷新数据,用于下拉刷新时调用
Future<void> refreshData() async {
// 这里可以实现刷新逻辑,比如重新获取二维码数据和密钥
await Future.delayed(const Duration(milliseconds: 500));
// 模拟更新数据,实际应用中可能需要调用API
// qrData.value = '更新后的二维码数据';
// secretKey.value = '更新后的密钥';
}
// 粘贴验证码
void pasteCode() async {
final clipboardData = await Clipboard.getData(Clipboard.kTextPlain);
if (clipboardData != null && clipboardData.text != null) {
final code = clipboardData.text!.replaceAll(RegExp(r'[^0-9]'), '');
if (code.isNotEmpty) {
// 取前6位或全部
textEditingController.text =
code.length > 6 ? code.substring(0, 6) : code;
}
}
}
// 确认按钮点击处理
void onConfirmPressed() {
if (textEditingController.text.length == 6) {
// 实际应用中需验证输入的代码
// 此处仅做示例,直接返回成功
Get.back(result: true);
} else {
// 显示错误动画
errorController.add(ErrorAnimationType.shake);
}
}
@override
void onClose() {
print('==========> FAGoogleCreateLogic onClose: ${identityHashCode(this)}');
textEditingController.dispose();
errorController.close();
super.onClose();
}
}
// 创建一个绑定类
// class FAGoogleCreateBinding extends Bindings {
// @override
// void dependencies() {
// print('==========> FAGoogleCreateBinding dependencies');
// // 尝试删除已有实例
// if (Get.isRegistered<FAGoogleCreateLogic>()) {
// print('==========> 发现已注册的控制器,正在移除');
// Get.delete<FAGoogleCreateLogic>(force: true);
// }
// // 使用Get.put替代Get.lazyPut
// Get.put(FAGoogleCreateLogic(), permanent: false);
// }
// }
class FAGoogleCreatePage extends StatelessWidget {
static void launch() {
RouteManager.toPage(() => FAGoogleCreatePage());
}
final logic = Get.put<FAGoogleCreateLogic>(FAGoogleCreateLogic());
FAGoogleCreatePage({super.key});
@override
Widget build(BuildContext context) {
// 添加日志查看控制器实例
print('==========> FAGoogleCreatePage build 开始');
final logic = Get.find<FAGoogleCreateLogic>();
print('==========> Get.find 返回的控制器实例 controller hashCode: ${identityHashCode(logic)}');
return Scaffold(
backgroundColor: AppColors.background,
appBar: DesignAppBar(
title: LangKey.authenticator.faGoogleGuideTitle.tr,
),
body: SafeArea(
child: EasyRefresh(
onRefresh: logic.refreshData,
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 16.h),
// 顶部提示框
Container(
padding:
EdgeInsets.symmetric(horizontal: 12.w, vertical: 5.h),
decoration: BoxDecoration(
color: AppColors.colorBgTips,
borderRadius: BorderRadius.circular(10.r),
),
child: Text(
LangKey.authenticator.faGoogleAuthenticatorTips.tr,
style: TextStyle(
fontSize: 12.sp,
color: AppColors.text222,
),
),
),
SizedBox(height: 24.h),
// 二维码扫描说明
Text(
LangKey.authenticator.faGoogleAuthenticatorQrCodeTips.tr,
style: TextStyle(
fontSize: 14.sp,
color: AppColors.textThird,
),
),
SizedBox(height: 24.h),
// 二维码显示
Center(
child: Container(
width: 160.w,
height: 160.w,
padding: EdgeInsets.all(8.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.r),
),
child: Obx(() {
return Image.network(
'https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${logic.qrData.value}',
width: 160.w,
height: 160.w,
errorBuilder: (context, error, stackTrace) {
return Center(
child: Icon(
Icons.qr_code,
size: 100.w,
color: Colors.black,
),
);
},
);
}),
),
),
SizedBox(height: 24.h),
// 密钥显示区域
Container(
padding: EdgeInsets.symmetric(horizontal: 16.w),
width: double.infinity,
height: 48.h,
decoration: BoxDecoration(
color: AppColors.color2B,
borderRadius: BorderRadius.circular(8.r),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Obx(() => Text(
logic.secretKey.value,
style: TextStyle(
fontSize: 16.sp,
color: AppColors.textWhite,
),
)),
GestureDetector(
onTap: logic.copySecretKey,
child: Icon(
Icons.copy,
color: AppColors.textWhite,
size: 20.w,
),
),
],
),
),
SizedBox(height: 16.h),
// Authenticator app code 标签
Text(
LangKey
.authenticator.faGoogleAuthenticatorCodeVerifyTips.tr,
style: TextStyle(
fontSize: 14.sp,
color: AppColors.textPrimary,
),
),
SizedBox(height: 8.h),
// 验证码输入框 - 使用PinCodeTextField替代
PinCodeTextField(
appContext: context,
length: 6,
animationType: AnimationType.fade,
pinTheme: PinTheme(
shape: PinCodeFieldShape.box,
borderRadius: BorderRadius.circular(8.r),
fieldHeight: 62.h,
fieldWidth: 46.w,
activeFillColor: AppColors.editBg,
inactiveFillColor: AppColors.editBg,
selectedFillColor: AppColors.editBg,
activeColor: AppColors.textSecondary,
inactiveColor: Colors.transparent,
selectedColor: AppColors.textSecondary,
borderWidth: 1.w,
activeBorderWidth: 1.w,
selectedBorderWidth: 1.w,
inactiveBorderWidth: 1.w,
errorBorderColor: AppColors.error,
errorBorderWidth: 1.w,
),
cursorColor: AppColors.brand,
animationDuration: const Duration(milliseconds: 300),
enableActiveFill: true,
keyboardType: TextInputType.number,
controller: logic.textEditingController,
errorAnimationController: logic.errorController,
onCompleted: (value) {
// 验证码输入完成的回调,可以自动触发确认
// logic.onConfirmPressed();
},
onChanged: (value) {
// 输入变化的回调
},
beforeTextPaste: (text) {
// 粘贴前的回调,返回 true 允许粘贴
return true;
},
textStyle: TextStyle(
fontSize: 24.sp,
color: AppColors.textPrimary,
fontWeight: FontWeight.w500,
),
),
// Paste 按钮
GestureDetector(
onTap: logic.pasteCode,
child: Text(
LangKey.common.paste.tr,
style: TextStyle(
color: AppColors.textLink,
fontSize: 12.sp,
),
),
),
SizedBox(height: 36.h),
],
),
),
),
),
),
bottomNavigationBar: SafeArea(
child: Padding(
padding: EdgeInsets.only(left: 16.w, right: 16.w, bottom: 16.h),
child: DesignButtonMatchWidth(
text: LangKey.common.confirm.tr,
onPressed: logic.onConfirmPressed,
),
),
),
);
}
}
To Reproduce Steps to reproduce the behavior:
- Go to 'FAGoogleCreatePage'
- Click on 'back' the Controller instances call onClose() function
- Second time go to 'FAGoogleCreatePage'
- the Controller instances still in and the onInit() function not call
Expected behavior the Controller instances call onClose() function and destory
Screenshots
Flutter Version: 3.29.1
Getx Version: get: ^4.7.2
Describe on which device you found the bug: ex: all the device also in ios simulator
new discovery, when I use Get.create, it performance good, the controller destory when call onClose().
final logic =
Get.create<FAGoogleCreateLogic>(() => FAGoogleCreateLogic(), permanent: false);
put the controller inside binding or put the controller inside init state on GetBuilder
put the controller inside binding or put the controller inside init state on GetBuilder
I tried put the controller inside binding and it's not work.
waiting for you GetX version 5, I will test my code on it.
for currently, I used Get.create to resolve this issue.
Use GetBuilder
Use GetBuilder
thks, I will try it later
老哥,你这样跳转就会自动释放掉的。Get.to(() => FAGoogleCreatePage()),()=> 不能少。