flutter - setState() 或 markNeedsBuild() 在构建期间调用,使用 FutureBuilder 中的 Provider 和 Flutter 中的 StreamBuilder
问题描述
我有以下问题。当我的应用程序启动(用户登录)时,我需要从 firebase 读取值accountId
- 这是与用户帐户分开创建的帐户的 ID,该帐户存储在 Firestore 文档之一中。accountId
通过嵌套的 FutureBuilder获取后main.dart
,我将其保存通过
Provider.of<RegistrationHelper>(context.updateAccountId(accountId);
到我的班级RegistrationHelper
,使其可用于其他地方。
问题是,虽然accountId
保存在 中RegistrationHelper
,但我收到以下错误,您可以在底部找到。这是我的代码main.dart
。有谁知道如何解决这个问题?非常感谢您的支持!
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(JustAnApp());
}
class EmotionsApp extends StatelessWidget {
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<RegistrationHelper>(
create: (_) => RegistrationHelper(),
),
ChangeNotifierProvider<EmotionsHelper>(
create: (_) => EmotionsHelper(),
),
],
child: MaterialApp(
title: 'Jak się dziś czujesz?',
theme: ThemeData(
primarySwatch: Colors.purple,
accentColor: Colors.orange,
accentColorBrightness: Brightness.light,
canvasColor: Color.fromRGBO(255, 254, 229, 1),
backgroundColor: Colors.deepPurple,
buttonTheme: ButtonTheme.of(context).copyWith(
buttonColor: Colors.purple,
textTheme: ButtonTextTheme.primary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
fontFamily: 'Raleway',
textTheme: ThemeData.light().textTheme.copyWith(
bodyText1: TextStyle(
color: Color.fromRGBO(20, 51, 51, 1),
),
bodyText2: TextStyle(
color: Color.fromRGBO(20, 51, 51, 1),
),
headline1: TextStyle(
fontSize: 20,
fontFamily: 'RobotoCondensed',
fontWeight: FontWeight.bold,
),
),
),
home: FutureBuilder(
future: _initialization,
builder: (context, snapshot) {
if (snapshot.hasError) {
print('Snapshot error (main.dart) : ${snapshot.error}');
return SomethingWentWrong();
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.connectionState == ConnectionState.done) {
// print('Snapshot (main.dart) : ${snapshot.connectionState}');
return StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, streamSnapshot) {
if (streamSnapshot.data == null) return LoginScreen();
if (streamSnapshot.connectionState ==
ConnectionState.waiting)
return Center(
child: CircularProgressIndicator(),
);
if (streamSnapshot.hasData) {
//print('MAIN.DART streamSnapshot data: $streamSnapshot');
final user = FirebaseAuth.instance.currentUser;
return FutureBuilder(
//HERE IS WHERE I AM FETCHING ACCOUNT ID
future: FirebaseFirestore.instance
.collection('root')
.doc('users')
.collection('userData')
.doc(user!.uid)
.get(),
builder: (BuildContext context, AsyncSnapshot snap) {
if (snap.data == null)
return Center(child: CircularProgressIndicator());
if (snap.connectionState == ConnectionState.waiting)
return Center(
child: CircularProgressIndicator(),
);
if (snap.hasData) {
//AND HERE I AM STORING ACCOUNT ID TO REGISTRATION HELPER CLASS
Provider.of<RegistrationHelper>(context)
.updateActualAccountId(
snap.data['accountId']);
//return Text('accountId updated');
}
return FacilitiesScreen();
});
} else {
return LoginScreen();
}
});
}
return Center(child: CircularProgressIndicator());
},
),
routes: {
...
},
),
);
}
}
以及 RegistrationHelper 中的一个简单方法:
void updateActualAccountId(String accountId) {
actualAccountId = accountId;
notifyListeners();
}
我得到的错误:
======== Exception caught by foundation library ====================================================
The following assertion was thrown while dispatching notifications for RegistrationHelper:
setState() or markNeedsBuild() called during build.
This _InheritedProviderScope<RegistrationHelper> widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: _InheritedProviderScope<RegistrationHelper>
value: Instance of 'RegistrationHelper'
listening to value
The widget which was currently being built when the offending call was made was: FutureBuilder<DocumentSnapshot<Map<String, dynamic>>>
dirty
state: _FutureBuilderState<DocumentSnapshot<Map<String, dynamic>>>#bdfb1
When the exception was thrown, this was the stack:
#0 Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:4305:11)
#1 Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4320:6)
#2 _InheritedProviderScopeElement.markNeedsNotifyDependents (package:provider/src/inherited_provider.dart:531:5)
#3 ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:308:24)
#4 RegistrationHelper.updateActualAccountId (package:emotions4_flutter/auth/auth_registration_helper.dart:42:5)
#5 _FacilitiesScreenState._updateAccountId (package:emotions4_flutter/screens/facilities_screen.dart:27:10)
#6 _FacilitiesScreenState.build.<anonymous closure> (package:emotions4_flutter/screens/facilities_screen.dart:101:25)
#7 _FutureBuilderState.build (package:flutter/src/widgets/async.dart:782:55)
#8 StatefulElement.build (package:flutter/src/widgets/framework.dart:4782:27)
#9 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4665:15)
#10 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4840:11)
#11 Element.rebuild (package:flutter/src/widgets/framework.dart:4355:5)
#12 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2620:33)
#13 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:882:21)
#14 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:319:5)
#15 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1143:15)
#16 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1080:9)
#17 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:996:5)
#21 _invoke (dart:ui/hooks.dart:166:10)
#22 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:270:5)
#23 _drawFrame (dart:ui/hooks.dart:129:31)
(elided 3 frames from dart:async)
The RegistrationHelper sending notification was: Instance of 'RegistrationHelper'
====================================================================================================
解决方案
似乎有效的解决方案是从主屏幕文件(不是来自 main.dart)的“didChangeDependencies”调用 RegistrationHelper 方法,如下所示:
@override
void didChangeDependencies() {
Provider.of<RegistrationHelper>(context, listen: false).getAccountId();
super.didChangeDependencies();
}
没有错误了。非常感谢你的帮助!
推荐阅读
- javascript - “.push in array”的未捕获类型错误
- r - 无法添加 git url 以将 Rstudio 中的项目与 git 存储库连接
- controller - 具有更多闪存的控制器是否消耗更多能量
- python - 如何在for循环python中向np数组添加一行
- html - 图像的引导列不会内联
- android - 华硕触摸屏显示器和安卓设备的问题
- selenium - 将参数传递给 Junit 5 TestRunner 扩展
- regex - 正则表达式逐位输入十进制数
- scala - spark-rdbms :覆盖模式的工作方式与 Append 不同
- android - Android FirebaseAuth 未记录的`getAccessToken`