flutter 打开键盘会导致有状态微件重新初始化

nwnhqdif  于 2023-01-27  发布在  Flutter
关注(0)|答案(5)|浏览(250)

我在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()方法。我使用print语句验证了这一点。
只有当我在弹回A之前打开键盘时才会发生这种情况。如果我导航到B,然后立即导航回A,而不与任何东西交互,那么A将保持其状态,不会重新初始化。
据我所知,build方法一直被调用,但是initState()不应该像这样被调用。有人知道这是怎么回事吗?

ruoxqz4g

ruoxqz4g1#

经过反复试验,我确定了问题所在。我忘记了我已经在MaterialApp小部件中为/路由设置了FutureBuilder。我传递了一个函数调用,该函数调用返回一个future到FutureBuilder构造函数的future参数,而不是指向future的变量。
因此,每次更新路径时,都会创建一个全新的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) {
          ...
          }
      ...
  }
  ...
}
gudnpqoy

gudnpqoy2#

您是否在“A”小工具中使用了AutomaticKeepAliveClientMixin?如果您没有,请查看此https://stackoverflow.com/a/51738269/3542938如果您已经使用它,请给予我们一个代码,我们可以直接在“main.dart”中测试它以帮助您

aiqt4smr

aiqt4smr3#

是的,发生在我身上,也许把FutureBuilder Package 成一个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>( ... );
      }
    }
6qfn3psc

6qfn3psc4#

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

b09cbbtk

b09cbbtk5#

我刚刚从MaterialApp的主目录中删除了FutureBuilder,并将MyApp更改为一个有状态小部件,在initState中获取了必要的信息,并在**. then()中调用了setState;* *,而不是在MaterialApp的主目录中传递多个条件,我将这些条件移动到一个单独的有状态小部件中,问题得到了解决。

    • 初始状态:**
@override
  void initState() {
    // TODO: implement initState
    // isSignedIn = SharedPrefHelper.getIsSignedIn();

    getIsSignedInFromSharedPreference().then((value) {
      setState(() {
        isSignedInFromSharedPref = value ?? false;
        if (isSignedInFromSharedPref) {
          merchantKey = LocalDatabase.getMerchantKeyWithoutAsync();
        }
        isLoadingSharedPrefValue = false;
      });
    });
    super.initState();
  }

  Future<bool?> getIsSignedInFromSharedPreference() async {
    return SharedPrefHelper.getIsSignedIn();
  }
    • 材料应用程序(现在):**
MaterialApp(
        title: 'Loveeatry POS',
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: Home(
          isLoadingSharedPrefValue: isLoadingSharedPrefValue,
          isSignedInFromSharedPref: isSignedInFromSharedPref,
          merchantKey: merchantKey,
        ),
      ),
    • 家:**
class Home extends StatelessWidget {
  final bool isLoadingSharedPrefValue;
  final bool isSignedInFromSharedPref;
  final String merchantKey;
  const Home({
    Key? key,
    required this.isLoadingSharedPrefValue,
    required this.isSignedInFromSharedPref,
    required this.merchantKey,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    if (!isLoadingSharedPrefValue) {
      if (isSignedInFromSharedPref) {
        return const Homepage(
          shouldLoadEverything: true,
        );
      } else if (merchantKey.isNotEmpty) {
        return LoginPage(merchantKey: merchantKey);
      } else {
        return const AddMerchantKeyPage();
      }
    } else {
      return loading(context);
    }
  }
}

如果您需要更多的信息,请留下评论。

相关问题