Flutter - TextEditingController 在处理后使用
Flutter - TextEditingController used after being disposed
我做了以下简单的 class 以允许输入字符串:
import 'package:flutter/material.dart';
class MyDialog {
late TextEditingController _controller;
Future<String> showMyDialog(BuildContext context) async {
_controller = TextEditingController();
final result = await showDialog(
context: context,
builder: (BuildContext context) => _buildMyDialog(context),
);
_controller.dispose();
return result;
}
Widget _buildMyDialog(BuildContext context) {
return AlertDialog(
title: const Text('Enter string: '),
content: TextField(
autofocus: true,
controller: _controller,
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(_controller.text);
},
child: const Text('OK'),
),
],
);
}
}
我这样称呼它:
final dialog = MyDialog();
final result = await dialog.showMyDialog(context);
不幸的是,我收到以下错误:
A TextEditingController was used after being disposed.
为什么会发生以及如何解决?毕竟我把控制器扔掉后就不会在任何地方使用了。
在showMyDialog
上每次都更新TextEditingController
,我们可以评论_controller.dispose();
。此外,有可能在此方法上获得 null,因此使用
会更好
Future<String?> showMyDialog(...){...}
我们可以做的另一件事是让它可以为空
class MyDialog {
TextEditingController? _controller;
Future<String?> showMyDialog(BuildContext context) async {
_controller = TextEditingController();
final String? result = await showDialog(
context: context,
builder: (BuildContext context) => _buildMyDialog(context),
);
_controller = null;
return result;
}
//....
你可以查看一下
我对 Yeasin 的回答 (在撰写本文时) 的担忧是你没有在控制器上调用 dispose()
而且我不是 100% 确定什么是无效的在这方面,实例确实如此。它可能会避免错误,但可能存在内存泄漏或其他问题(假设)。
我建议的另一种方法是将您的 AlertDialog
变成 StatefulWidget
,这样您就可以利用 Widgets 的内置 dispose()
方法。这将使您避免对控制器进行微观管理。相反,您在包含控制器的 Widget 的 dispose 方法中调用控制器的 dispose 方法。
下面是您的代码利用 Flutter 的这一功能的样子,它不会改变您调用代码以显示对话框的方式:
class MyDialog {
Future<String> showMyDialog(BuildContext context) async {
final result = await showDialog(
context: context,
builder: (BuildContext context) => MyAlertDialog(),
);
return result;
}
}
class MyAlertDialog extends StatefulWidget {
@override
MyAlertDialog createState() => MyAlertDialogState();
}
class MyAlertDialogState extends State<MyAlertDialog> {
// for this example, it's safe to instantiate the controller inline
TextEditingController _controller = new TextEditingController();
@override
void dispose() {
// attempt to dispose controller when Widget is disposed
try { _controller.dispose(); } catch (e) {}
}
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('Enter string: '),
content: TextField(
autofocus: true,
controller: _controller,
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(_controller.text);
},
child: const Text('OK'),
),
],
);
}
}
我做了以下简单的 class 以允许输入字符串:
import 'package:flutter/material.dart';
class MyDialog {
late TextEditingController _controller;
Future<String> showMyDialog(BuildContext context) async {
_controller = TextEditingController();
final result = await showDialog(
context: context,
builder: (BuildContext context) => _buildMyDialog(context),
);
_controller.dispose();
return result;
}
Widget _buildMyDialog(BuildContext context) {
return AlertDialog(
title: const Text('Enter string: '),
content: TextField(
autofocus: true,
controller: _controller,
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(_controller.text);
},
child: const Text('OK'),
),
],
);
}
}
我这样称呼它:
final dialog = MyDialog();
final result = await dialog.showMyDialog(context);
不幸的是,我收到以下错误:
A TextEditingController was used after being disposed.
为什么会发生以及如何解决?毕竟我把控制器扔掉后就不会在任何地方使用了。
在showMyDialog
上每次都更新TextEditingController
,我们可以评论_controller.dispose();
。此外,有可能在此方法上获得 null,因此使用
Future<String?> showMyDialog(...){...}
我们可以做的另一件事是让它可以为空
class MyDialog {
TextEditingController? _controller;
Future<String?> showMyDialog(BuildContext context) async {
_controller = TextEditingController();
final String? result = await showDialog(
context: context,
builder: (BuildContext context) => _buildMyDialog(context),
);
_controller = null;
return result;
}
//....
你可以查看一下
我对 Yeasin 的回答 (在撰写本文时) 的担忧是你没有在控制器上调用 dispose()
而且我不是 100% 确定什么是无效的在这方面,实例确实如此。它可能会避免错误,但可能存在内存泄漏或其他问题(假设)。
我建议的另一种方法是将您的 AlertDialog
变成 StatefulWidget
,这样您就可以利用 Widgets 的内置 dispose()
方法。这将使您避免对控制器进行微观管理。相反,您在包含控制器的 Widget 的 dispose 方法中调用控制器的 dispose 方法。
下面是您的代码利用 Flutter 的这一功能的样子,它不会改变您调用代码以显示对话框的方式:
class MyDialog {
Future<String> showMyDialog(BuildContext context) async {
final result = await showDialog(
context: context,
builder: (BuildContext context) => MyAlertDialog(),
);
return result;
}
}
class MyAlertDialog extends StatefulWidget {
@override
MyAlertDialog createState() => MyAlertDialogState();
}
class MyAlertDialogState extends State<MyAlertDialog> {
// for this example, it's safe to instantiate the controller inline
TextEditingController _controller = new TextEditingController();
@override
void dispose() {
// attempt to dispose controller when Widget is disposed
try { _controller.dispose(); } catch (e) {}
}
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('Enter string: '),
content: TextField(
autofocus: true,
controller: _controller,
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(_controller.text);
},
child: const Text('OK'),
),
],
);
}
}