颤振:使用提供程序时,状态在热重载时丢失

Posted

技术标签:

【中文标题】颤振:使用提供程序时,状态在热重载时丢失【英文标题】:flutter: State is lost on Hot Reload when using Provider 【发布时间】:2019-10-28 01:50:47 【问题描述】:

我正在使用 Provider 来管理我的应用程序的状态。以下是我的实现方式。

hypnose.dart

class _HypnoseAppState extends State<HypnoseApp> 
  @override
  Widget build(BuildContext context) 
    UserService userService = UserService();
    AudioUtilService audioUtilService = AudioUtilService();

    return MultiProvider(
      providers: [
        ChangeNotifierProvider<UserService>.value(
          value: userService,
        ),
        ChangeNotifierProvider<AudioUtilService>.value(
          value: audioUtilService,
        )
      ],
      child: MaterialApp(
          debugShowCheckedModeBanner: false,
          title: Globals.title,
          theme: ThemeData(primarySwatch: Colors.cyan),
          darkTheme: ThemeData.dark(),
          initialRoute: '/',
          routes: 
            '/': (BuildContext context) => WelcomeScreen(userService),
            '/home': (BuildContext context) => HomePageSwitcher(),
            '/audiocreate': (BuildContext context) => AudioCreateScreen()
          ),
    );
  

home_switcher.dart

class HomePageSwitcher extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return Consumer<UserService>(
      builder: (BuildContext context, UserService userService, Widget child) 
        return Scaffold(
            appBar: AppBar(),
            drawer: Drawer(
              child: Column(
                children: <Widget>[
                  UserAccountsDrawerHeader(
                    accountEmail: Text(userService.loggedInUser.email),
                    accountName: Text(userService.loggedInUser.name),
                    currentAccountPicture:
                        Image.network(userService.loggedInUser.avatar),
                  )
                ],
              ),
            ),
            body: Center(
              child: RaisedButton(
                child: Text('Sign out'),
                onPressed: () async 
                  await userService.signOut();
                  Navigator.pushNamed(context, '/');
                ,
              ),
            ));
      ,
    );
  

user_service.dart

class UserService extends ChangeNotifier 
  // Get auth instances
  final GoogleSignIn _googleSignIn = GoogleSignIn();
  final FirebaseAuth _auth = FirebaseAuth.instance;

  // Store reference of user collection
  final CollectionReference userDb = Firestore.instance.collection('user');

  // Master instance of logged in user
  User _loggedInUser;

  // Getter to access loggedInUser
  User get loggedInUser 
    return _loggedInUser;
  

  PublishSubject<AuthState> _authStateSubject = PublishSubject();

.... other code

现在这里的问题是,每次我热重载时,在主页上,我开始收到 NoSuchMethodError,因为它说电子邮件、姓名等属性被调用为 null,我认为这意味着状态是丢失。我怎样才能克服同样的问题?我做错了吗?

【问题讨论】:

【参考方案1】:

您不应使用ChangeNotifierProvider.value。而是使用默认构造函数:

ChangeNotifierProvider(
  builder: (_) => UserService(),
)

否则,您的构建方法不纯,您将遇到How to deal with unwanted widget build? 中所述的问题

【讨论】:

我看到很多例子都说 UserService() 而不是对象 userService。它必须是一个新实例化的对象吗?因为我不知道如何将它与新设置的值一起使用。 @chitgoks 如文档所述,如果您已经有一个对象实例,则可以使用ChangeNotifierProvider.value 我改用了 ProxyProvider。因为我的变量属性发生了变化。 我遇到了完全相同的问题,即使在 4.0.4 上使用 create: (_) =&gt; UserService(), 也是如此 @RémiRousselet 你太棒了。按照您的链接。我知道如果您执行路线,提供者也会失去状态。在 notifyListener() 之前。【参考方案2】:

构建方法的设计方式应该是纯的/没有副作用。这是因为许多外部因素都可以触发新的小部件构建,例如:

Route pop/push
Screen resize, usually due to keyboard appearance or orientation change
Parent widget recreated its child
An InheritedWidget the widget depends on (Class.of(context) pattern) change

这意味着构建方法不应触发 http 调用或修改任何状态。

这与问题有什么关系?

您面临的问题是您的构建方法有副作用/不纯,使得无关的构建调用很麻烦。

您应该使您的构建方法纯粹,而不是阻止构建调用,以便可以随时调用它而不会受到影响。

在您的示例中,您需要将小部件转换为 StatefulWidget,然后将该 HTTP 调用提取到您的 State 的 initState:

ChangeNotifierProvider(
    create: (_) => UserService(),
),

【讨论】:

以上是关于颤振:使用提供程序时,状态在热重载时丢失的主要内容,如果未能解决你的问题,请参考以下文章

Flutter Provider 仅在热重载后显示结果

当手机进入睡眠状态时,颤振热重载停止工作

Flutter:应用程序在热重载后不断回到初始路线

使用提供程序包 FLUTTER 关闭应用程序后保存状态

颤振热重载和热重启不起作用

颤振热重载不适用于平板电脑模拟器