Flutter MultiProvider:setState()或markNeedsBuild()在生成过程中调用



当我这样做时:

import 'package:blogs/common/theme.dart';
import 'package:blogs/screen/home.dart';
import 'package:blogs/state/authstate.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(
MultiProvider(
providers: [ChangeNotifierProvider(create: (context) => AuthState())],
child: const MyApp(),
)
);
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
var authState = context.watch<AuthState>();
if (authState.idToken == null) {
authState.signInWithAutoCodeExchange();
}
return MaterialApp(
title: 'Blogs',
theme: appTheme,
initialRoute: '/',
routes: {'/': (context) => const Home()},
);
}
}

我得到

======== Exception caught by foundation library ====================================================
The following assertion was thrown while dispatching notifications for AuthState:
setState() or markNeedsBuild() called during build.
This _InheritedProviderScope<AuthState?> 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<AuthState?>
value: Instance of 'AuthState'
listening to value
The widget which was currently being built when the offending call was made was: MyApp
dirty
dependencies: [_InheritedProviderScope<AuthState?>]
When the exception was thrown, this was the stack: 
#0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:4424:11)
#1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4439:6)
#2      _InheritedProviderScopeElement.markNeedsNotifyDependents (package:provider/src/inherited_provider.dart:570:5)
#3      ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:308:24)
#4      AuthState.isBusy= (package:blogs/state/authstate.dart:20:5)
#5      AuthState.setBusyState (package:blogs/state/authstate.dart:210:5)
#6      AuthState.signInWithAutoCodeExchange (package:blogs/state/authstate.dart:175:7)
#7      MyApp.build (package:blogs/main.dart:21:17)
#8      StatelessElement.build (package:flutter/src/widgets/framework.dart:4827:28)
#9      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4754:15)
#10     Element.rebuild (package:flutter/src/widgets/framework.dart:4477:5)
#11     ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4735:5)
#12     ComponentElement.mount (package:flutter/src/widgets/framework.dart:4729:5)
#13     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3790:14)
#14     Element.updateChild (package:flutter/src/widgets/framework.dart:3540:18)
#15     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4780:16)
#16     _InheritedProviderScopeElement.performRebuild (package:provider/src/inherited_provider.dart:495:11)
#17     Element.rebuild (package:flutter/src/widgets/framework.dart:4477:5)
#18     ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4735:5)
#19     ComponentElement.mount (package:flutter/src/widgets/framework.dart:4729:5)
#20     _InheritedProviderScopeElement.mount (package:provider/src/inherited_provider.dart:395:11)
...     Normal element mounting (7 frames)
#27     SingleChildWidgetElementMixin.mount (package:nested/nested.dart:222:11)
...     Normal element mounting (7 frames)
#34     _NestedHookElement.mount (package:nested/nested.dart:187:11)
...     Normal element mounting (7 frames)
#41     SingleChildWidgetElementMixin.mount (package:nested/nested.dart:222:11)
#42     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3790:14)
#43     Element.updateChild (package:flutter/src/widgets/framework.dart:3540:18)
#44     RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1198:16)
#45     RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:1167:5)
#46     RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:1112:18)
#47     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2600:19)
#48     RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1111:13)
#49     WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:944:7)
#50     WidgetsBinding.scheduleAttachRootWidget.<anonymous closure> (package:flutter/src/widgets/binding.dart:924:7)
(elided 11 frames from class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch)
The AuthState sending notification was: Instance of 'AuthState'
====================================================================================================

但当我这样做时:

import 'package:blogs/common/theme.dart';
import 'package:blogs/screen/home.dart';
import 'package:blogs/state/authstate.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [ChangeNotifierProvider(create: (context) => AuthState())], 
child: MaterialApp(
title: 'Blogs',
theme: appTheme,
initialRoute: '/',
routes: {'/': (context) => const Home()},
),
);
}
}

我不能有

var authState = context.watch<AuthState>();
if (authState.idToken == null) {
authState.signInWithAutoCodeExchange();
}

在调用第一个路由之前。

然而,应用程序启动并正常运行,因为错误输出状态为"0";允许异常";。

我现在发现罪魁祸首是

if (authState.idToken == null) {
authState.signInWithAutoCodeExchange();
}

我猜在建筑完工之前就已经进入了状态。

我想也许可以把它全部封装在一个小部件中,但我需要以某种方式确保在访问状态之前构建已经完成。我该如何确保情况确实如此?

我认为这不是解决这个问题的正确方法。是否有更好或更优雅的解决方案来要求用户进行身份验证?

我认为发生这个错误是因为您试图在flutter完成构建小部件树之前调用上下文。

在flutter完成小部件的构建之后,将其用于flutter来执行代码。

WidgetsBinding.instance.addPostFrameCallback((_) {// your code in here});

相关内容

最新更新