如何处理和重新创建一些状态

Mar*_*rcG 8 lifecycle widget flutter

请考虑下面的代码。

在 initState 期间创建了一个 textController。如果按下按钮,则会在 setState 内部创建另一个 textController:

import 'package:flutter/material.dart';

void main() { runApp(Test()); }

class Test extends StatefulWidget {
  TestState createState() => TestState();
}

class TestState extends State<Test> {
  TextEditingController textController;

  void initState() {
    print("initState");
    super.initState();

    textController = TextEditingController(text: "1st textController");
  }

  void dispose() {
    print("dispose");
    textController.dispose();
    super.dispose();
  }

  void onPressed() {
    print("onPressed");

    setState(() {
      print("setState");

      // It breaks if this line is uncommented.
      if (textController != null) textController.dispose();

      textController = TextEditingController(text: "2nd textController");
    });
  }

  Widget build(BuildContext context) {
    print("build");

    var button = MaterialButton(onPressed: onPressed, child: const Text("Click Me"));
    var textField = TextField(keyboardType: TextInputType.number, controller: textController);

    return MaterialApp(
      home: Material(
        child: Padding(
          padding: const EdgeInsets.all(30.0),
          child: Column(children: [button, textField]),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

有用。但是,我从未处理过旧的 textController。在创建新的 textController 之前,我可以在 setState 内部执行此操作:

    setState(() {
      print("setState");
      if (textController != null) textController.dispose();
      textController = TextEditingController(text: "2nd textController");
    });
Run Code Online (Sandbox Code Playgroud)

但是,然后,我收到一个错误:

??? EXCEPTION CAUGHT BY WIDGETS LIBRARY ???
I/flutter ( 4645): The following assertion was thrown building             
InputDecorator(decoration: InputDecoration(), isFocused:
I/flutter ( 4645): false, isEmpty: false, state:     
_InputDecoratorState#8195a(tickers: tracking 2 tickers)):
I/flutter ( 4645): A TextEditingController was used after being disposed.
I/flutter ( 4645): Once you have called dispose() on a TextEditingController, it can no longer be used.
Run Code Online (Sandbox Code Playgroud)

我的问题:

1)为什么我会收到这个错误?textControlled 还在使用吗?在哪里?

2)如何解决这个问题?

小智 1

我有一些可能对您有所帮助的观察结果,此外,我还准备了一个代码示例。

首先,无需重新创建,因为通常每个, 或TextEditingController都会有一个(取决于实现)。您也可以将其声明为不需要使用.TextFieldTextFormFieldfinalinitState()

dispose()其次,当不再需要TextEditingController 时,请记住将其丢弃。这将确保我们丢弃该对象使用的任何资源。使用时无需丢弃。请记住:控制器不会通知侦听器文本输入字段内的更改。

import 'package:flutter/material.dart';

// Main method
void main() {
  runApp(App());
}

// I've made a separate App class that returns MaterialApp
class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HomeScreen(),
    );
  }
}

// HomeScreen replaces your Test
class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  // TextEditingController could have been declared final here
  // as well, for example:
  //
  //  final _controller = TextEditingController(text: 'default');
  //
  // but take that as a suggestion for future ;)
  TextEditingController _controller;

  // String we'll be changing
  String _mutableTextString = '';

  @override
  void initState() {
    super.initState();

    // Simple declarations
    _controller = TextEditingController(text: 'default');
    _mutableTextString = _controller.text;
  }

  @override
  void dispose() {
    // Call the dispose() method of the TextEditingController
    // here, and remember to do it before the super call, as
    // per official documentation:
    // https://api.flutter.dev/flutter/widgets/TextEditingController-class.html
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        minimum: const EdgeInsets.all(30.0),
        child: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              TextField(
                controller: _controller,
                keyboardType: TextInputType.text,
              ),
              MaterialButton(
                child: Text('CLICK ME'),
                onPressed: _handleOnPressed,
              ),
              Text(_mutableTextString),
            ],
          ),
        ),
      ),
    );
  }

  // This method handles actions when the button is pressed
  // and updates the UI
  void _handleOnPressed() {
    setState(() {
      _mutableTextString = _controller.text;
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

我也为您准备了一个简短的演示,希望对您有所帮助!

上面源码的demo