【问题标题】:Opening keyboard causes stateful widgets to be re-initialized打开键盘会导致有状态小部件重新初始化
【发布时间】:2023-03-20 10:00:01
【问题描述】:

我在 Stable 分支中使用 Flutter 1.2.1。为了说明我的问题,假设我有页面 A 和 B。A 使用 Navigator.push 导航到 B,B 使用 Navigator.pop 导航回 A。两者都是有状态的小部件。

当我从 A 导航到 B 然后弹回 A 时,一切都很好,A 保持其状态。但是,如果我从 A 导航到 B,点击 B 中的文本字段打开键盘,然后关闭键盘并弹回 A,则 A 的整个状态被刷新并再次调用 A 的 initState() 方法。我使用打印语句验证了这一点。

只有当我在返回 A 之前打开键盘时才会发生这种情况。如果我导航到 B,然后立即导航回 A 而不与任何东西交互,那么 A 会保持其状态并且不会重新初始化。

据我了解,build 方法一直被调用,但 initState() 不应该像这样被调用。有谁知道怎么回事?

【问题讨论】:

    标签: flutter


    【解决方案1】:

    你在“A”小部件中使用了AutomaticKeepAliveClientMixin 吗? 如果您不这样做,请参阅此https://stackoverflow.com/a/51738269/3542938 如果你已经在使用它,请给我们一个代码,我们可以直接在“main.dart”中测试它来帮助你

    【讨论】:

    • 感谢您的回答。直到今天早上我才能尝试这个。它没有用。键盘打开时似乎发生了一些事情,导致一切重新创建。这在 1.2 版之前不会发生。
    • 可能是一个错误,尝试报告颤振团队,通过以下公开问题:[github.com/flutter/flutter/issues]
    【解决方案2】:

    经过多次反复试验,我确定了问题所在。我忘记了我在MaterialApp 小部件中为/ 路由设置了FutureBuilder。我正在传递一个函数调用,该函数调用将未来返回给FutureBuilder 构造函数的future 参数,而不是指向未来的变量。

    因此,每次更新路线时,都会创建一个全新的未来。在MaterialApp 构造函数之外进行函数调用并将生成的future 存储在一个变量中,然后将其传递给FutureBuilder 就可以了。

    这似乎与我在打开键盘时遇到的奇怪行为有关,但这绝对是原因。我的意思见下文。

    有错误的代码:

    return MaterialApp(
      title: appTitle,
      theme: ThemeData(
        primarySwatch: Colors.teal,
        accentColor: Colors.tealAccent,
        buttonColor: Colors.lightBlue,
      ),
      routes: {
        '/': (context) => FutureBuilder<void>(
              future: futureFun(), //Bug! I'm passing a function that returns a future when called. So a new future is returned each time
              builder: (context, snapshot) {
              ...
              }
          ...
      }
      ...
    }
    

    固定代码:

    final futureVar = futureFun(); //calling the function here instead and storing its future in a variable
    
    return MaterialApp(
      title: appTitle,
      theme: ThemeData(
        primarySwatch: Colors.teal,
        accentColor: Colors.tealAccent,
        buttonColor: Colors.lightBlue,
      ),
      routes: {
        '/': (context) => FutureBuilder<void>(
              future: futureVar, //Fixed! Passing the reference to the future rather than the function call
              builder: (context, snapshot) {
              ...
              }
          ...
      }
      ...
    }
    

    【讨论】:

      【解决方案3】:

      是的,发生在我身上,也许将 FutureBuilder itu 包装为 PageWidget 并使其成为单例会更好

          return MaterialApp(
            title: appTitle,
            theme: ThemeData(
              primarySwatch: Colors.teal,
              accentColor: Colors.tealAccent,
              buttonColor: Colors.lightBlue,
            ),
            routes: {
              '/': (context) => PageWidget() // wrap it by PageWidget
                ...
            }
            ...
          }
      
      
          class PageWidget extends StatelessWidget {
            static final _instance = PageWidget._internal(); // hold instance
      
            PageWidget._internal(); // internal consturctor
      
            factory PageWidget() {
              return  _instance;    // make it singleton
            }
      
            @override
            Widget build(BuildContext context) {
              return FutureBuilder<void>( ... );
            }
          }
      

      【讨论】:

        【解决方案4】:

        我有一个解决方案,我在超类的构造函数中初始化变量。我删除了它并工作了!

        【讨论】:

          猜你喜欢
          • 2019-10-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-04-13
          • 2018-08-07
          相关资源
          最近更新 更多