颤振:使用提供程序时,状态在热重载时丢失
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: (_) => 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(),
),
【讨论】:
以上是关于颤振:使用提供程序时,状态在热重载时丢失的主要内容,如果未能解决你的问题,请参考以下文章