You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter求助:TextEditingController释放后仍被使用错误排查

问题分析与解决方案

错误信息

A texteditingcontroller was used after being disposed. Once you have called dispose() on aTextEditingController, it can no longer be used.

首次进入页面无报错,但返回后再次进入同一屏幕时触发该错误。

核心原因

你把TextEditingController和GlobalKey<FormState>定义在了StatefulWidget类的外部,变成了全局变量。当页面被销毁(调用dispose())时,这些控制器会被释放,但再次进入页面时,新创建的State会复用这个已经被dispose的全局控制器,从而触发报错。

解决方案

将FormKey和所有TextEditingController移到对应页面的State类内部,确保每次进入页面时都会创建全新的控制器实例,避免复用已销毁的对象。

修改后的SignInScreen代码

import 'package:batch8_taskmanager_project/ui/screens/sign_up_screen.dart';
import 'package:batch8_taskmanager_project/ui/widgets/screen_background.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

class SignInScreen extends StatefulWidget {
  const SignInScreen({super.key});

  static const String name = '/sign-in-screen';

  @override
  State<SignInScreen> createState() => _SignInScreenState();
}

class _SignInScreenState extends State<SignInScreen> {
  // 将FormKey和控制器移到State内部
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  final TextEditingController _emailTEController = TextEditingController();
  final TextEditingController _passwordTEController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    final textStyle = Theme.of(context).textTheme;

    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: ScreenBackground(
          child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              const SizedBox(height: 68),
              Text("Get Started With", style: textStyle.titleLarge),
              const SizedBox(height: 24),
              TextFormField(
                controller: _emailTEController,
                keyboardType: TextInputType.emailAddress,
                decoration: const InputDecoration(hintText: "Email Address"),
              ),
              const SizedBox(height: 24),
              TextFormField(
                controller: _passwordTEController,
                obscureText: true,
                decoration: const InputDecoration(hintText: "Password"),
              ),
              const SizedBox(height: 24),
              ElevatedButton(onPressed: () {}, child: const Icon(Icons.double_arrow)),
              const SizedBox(height: 48),
              TextButton(onPressed: () {}, child: const Text("Forgot Password?")),
              const SizedBox(height: 24),
              _buildSignIn()
            ],
          ),
        ),
      )),
    );
  }

  Widget _buildSignIn() {
    return RichText(
      text: TextSpan(
        text: "Don't have an account? ",
        style: const TextStyle(color: Colors.grey),
        children: [
          TextSpan(
            text: "Sign up",
            style: const TextStyle(color: Colors.green, fontWeight: FontWeight.bold),
            recognizer: TapGestureRecognizer()..onTap = () {
              Navigator.pushNamed(context, SignupScreen.name);
            }
          )
        ],
      ),
    );
  }

  @override
  void dispose() {
    _emailTEController.dispose();
    _passwordTEController.dispose();
    super.dispose();
  }
}

修改后的SignUpScreen代码

import 'package:batch8_taskmanager_project/ui/widgets/screen_background.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

class SignupScreen extends StatefulWidget {
  const SignupScreen({super.key});

  static const String name = '/sign-up-screen';

  @override
  State<SignupScreen> createState() => _SignupScreenState();
}

class _SignupScreenState extends State<SignupScreen> {
  // 将FormKey和控制器移到State内部
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  final TextEditingController _emailTEController = TextEditingController();
  final TextEditingController _firstNameTEController = TextEditingController();
  final TextEditingController _lastNameTEController = TextEditingController();
  final TextEditingController _mobileTEController = TextEditingController();
  final TextEditingController _passwordTEController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    final textStyle = Theme.of(context).textTheme;

    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: ScreenBackground(
          child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              const SizedBox(height: 68),
              Text("Join with Us", style: textStyle.titleLarge),
              const SizedBox(height: 24),
              TextFormField(
                controller: _emailTEController,
                keyboardType: TextInputType.emailAddress,
                decoration: const InputDecoration(hintText: "Email Address"),
              ),
              const SizedBox(height: 12),
              TextFormField(
                controller: _firstNameTEController,
                decoration: const InputDecoration(hintText: "First Name"),
              ),
              const SizedBox(height: 12),
              TextFormField(
                controller: _lastNameTEController,
                decoration: const InputDecoration(hintText: "Last Name"),
              ),
              const SizedBox(height: 12),
              TextFormField(
                controller: _mobileTEController,
                keyboardType: TextInputType.number,
                decoration: const InputDecoration(hintText: "Mobile"),
              ),
              const SizedBox(height: 12),
              TextFormField(
                controller: _passwordTEController,
                obscureText: true,
                decoration: const InputDecoration(hintText: "Password"),
              ),
              const SizedBox(height: 24),
              ElevatedButton(onPressed: () {}, child: const Icon(Icons.double_arrow)),
              const SizedBox(height: 48),
              _buildSignUp()
            ],
          ),
        ),
      )),
    );
  }

  Widget _buildSignUp() {
    return RichText(
      text: TextSpan(
        text: "Have an account? ",
        style: const TextStyle(color: Colors.grey),
        children: [
          TextSpan(
            text: "Sign in",
            style: const TextStyle(color: Colors.green, fontWeight: FontWeight.bold),
            recognizer: TapGestureRecognizer()..onTap = () {
              Navigator.pop(context);
            }
          )
        ],
      ),
    );
  }

  @override
  void dispose() {
    _emailTEController.dispose();
    _firstNameTEController.dispose();
    _lastNameTEController.dispose();
    _mobileTEController.dispose();
    _passwordTEController.dispose();
    super.dispose();
  }
}

原理说明

当StatefulWidget的实例被创建时,对应的State类也会被实例化,此时内部定义的控制器会重新创建,避免复用已被dispose的全局实例。页面销毁时,dispose()方法释放当前State实例的控制器,再次进入页面时,新的State会创建全新的控制器,不会出现“使用已销毁控制器”的错误。

内容的提问来源于stack exchange,提问作者Jahangir Alam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 08:17:03