无法将小部件标记为需要构建,因为框架已经在构建小部件的过程中
Posted
技术标签:
【中文标题】无法将小部件标记为需要构建,因为框架已经在构建小部件的过程中【英文标题】:Widget cannot be marked as needing to build because the framework is already in the process of building widgets 【发布时间】:2020-07-06 05:42:57 【问题描述】:我正在尝试实现 Provider,它似乎工作正常,但我收到以下消息:
这个 _DefaultInheritedProviderScope 小部件不能 标记为需要构建,因为框架已经在 构建小部件的过程。可以将小部件标记为需要 仅当其祖先之一当前处于构建阶段时才构建 建筑。允许此异常,因为框架构建 孩子之前的父小部件,这意味着脏后代将 总是被建造。否则,框架可能不会访问这个小部件 在此构建阶段。 setState() 或 markNeedsBuild() 被称为: _DefaultInheritedProviderScope 值:“UserProfile”实例监听值当前小部件 发出违规调用时正在构建的是:FutureBuilder 脏状态:_FutureBuilderState#bf6ec 异常发生时 抛出,这是堆栈:
0 元素.markNeedsBuild。 (包:flutter/src/widgets/framework.dart:3896:11)
1 Element.markNeedsBuild(包:flutter/src/widgets/framework.dart:3911:6)
2 _InheritedProviderScopeMixin.markNeedsNotifyDependents(包:provider/src/inherited_provider.dart:268:5)
3 ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:206:21)
4 UserProfile.user= (package:mdd/core/services/user_info.dart:13:5) ... UserProfile
发送通知是:'UserProfile'的实例
我的代码如下:
class HomePage extends StatelessWidget
@override
Widget build(BuildContext context)
final authService = Provider.of<AuthService>(context);
final userProfile = Provider.of<UserProfile>(context);
return StatefulWrapper(
onInit: ()
FirebaseNotifications().setUpFirebase();
,
child: FutureBuilder<User>(
future: authService.getUser(),
builder: (context, AsyncSnapshot<User> snapshot)
if (snapshot.connectionState == ConnectionState.done)
if (snapshot.error != null)
return Text(snapshot.error.toString());
userProfile.user = snapshot.data;
// FirebaseUser user = snapshot.data;
return snapshot.hasData ? ListScreen() : LoginScreen();
else
return Scaffold(
appBar: AppBar(),
body: Container(),
);
,
)
);
这是 UserProfile 类:
class UserProfile with ChangeNotifier
User _user = User();
get user
return _user;
set user(User user)
this._user = user;
notifyListeners();
以及用于获取配置文件的 AuthService 部分:
Future<User> getUser() async
print('GETTING THE USER');
final fbaseUser = await _auth.currentUser();
final snapshot = await _db.collection('users')
.document(fbaseUser.uid)
.get();
if (snapshot.data != null)
Map<dynamic, dynamic> jsres = snapshot.data;
_user = User.fromJson(jsres);
return _user;
为什么会出现此错误?我究竟做错了什么?有人可以帮我解决这个问题吗?
【问题讨论】:
【参考方案1】:您可以在下面复制粘贴运行完整代码,完整代码修复此问题
原因:
此行userProfile.user = snapshot.data;
导致错误FutureBuilder
是构建数据,并接收notifyListeners()
来自 Flutter 团队的建议,https://github.com/flutter/flutter/issues/16218#issuecomment-403995076FutureBuilder
的builder
应该只构建小部件,它不应该有任何逻辑。建设者可以被任意调用。
解决方案:
在用户情况下,getUser()
后面可以直接设置UserProfile.user
第 1 步:删除 final userProfile = Provider.of<UserProfile>(context);
第 2 步:将 userProfile.user = snapshot.data;
逻辑移动到 futureBuilder
的 future
FutureBuilder<User>(
future: _future.then((value) =>
Provider.of<UserProfile>(context, listen: false).user = value),
完整代码
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main()
runApp(
ChangeNotifierProvider(
create: (context) => UserProfile(),
child: MyApp(),
),
);
class StatefulWrapper extends StatefulWidget
final Function onInit;
final Widget child;
const StatefulWrapper(@required this.onInit, @required this.child);
@override
_StatefulWrapperState createState() => _StatefulWrapperState();
class _StatefulWrapperState extends State<StatefulWrapper>
@override
void initState()
if (widget.onInit != null)
widget.onInit();
super.initState();
@override
Widget build(BuildContext context)
return widget.child;
class User
String name;
User(this.name);
Future<User> getUser() async
print("getUser");
return User(name: "test");
class UserProfile with ChangeNotifier
User _user = User();
get user
return _user;
set user(User user)
this._user = user;
notifyListeners();
class HomePage extends StatelessWidget
@override
Widget build(BuildContext context)
//final authService = Provider.of<AuthService>(context);
//final userProfile = Provider.of<UserProfile>(context, listen: false);
Future _future = getUser();
return StatefulWrapper(
onInit: ()
//FirebaseNotifications().setUpFirebase();
,
child: FutureBuilder<User>(
future: _future.then((value) =>
Provider.of<UserProfile>(context, listen: false).user = value),
builder: (context, AsyncSnapshot<User> snapshot)
if (snapshot.connectionState == ConnectionState.done)
if (snapshot.error != null)
return Text(snapshot.error.toString());
if (snapshot.hasData)
return ListScreen();
else
return LoginScreen();
else
return Scaffold(
appBar: AppBar(),
body: Container(),
);
,
));
class ListScreen extends StatelessWidget
@override
Widget build(BuildContext context)
return Text("ListScreen");
class LoginScreen extends StatelessWidget
@override
Widget build(BuildContext context)
return Text("LoginScreen");
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
【讨论】:
谢谢!所以维护最终的 authService = Provider.of(context); 是没有问题的并使用它来能够在我想的未来参数中使用 authService.getUser 函数。我的意思是,我就是这样做的,而且效果很好,但只是为了确保这是一种愚蠢的做法。 如果遇到FutureBuilder不必要的重建,可以参考github.com/flutter/flutter/issues/11426#issuecomment-414047398【参考方案2】:有问题的代码:
if(condition)
...
...
notifyListners(); // problem
else
await Future....
...
...
notifyListners(); //not getting problem here
带有解决方案的代码:我没有使用等待,这就是为什么会出现错误。所以在使用 notifyListners() 之前,在异步函数中使用 await
if(condition)
...
...
await Future.delayed(Duration(milliseconds: 1)); // use await
notifyListners();
else
await Future....
...
...
notifyListners();
【讨论】:
【参考方案3】:当我收到这条消息时,发现在作为侦听器的小部件中有一个 notifylisteners()
调用。
我刚刚删除了多余的 notifyListeners()
调用,一切正常。
【讨论】:
【参考方案4】:之前
class UserProfile with ChangeNotifier
User _user = User();
get user
return _user;
set user(User user)
this._user = user;
notifyListeners();
再添加一个这样的方法
void Adduser(User user)
this._user = user;
在\Solution :now 通知模型类之后
class UserProfile with ChangeNotifier
User _user = User();
get user
return _user;
set user(User user)
this._user = user;
notifyListeners();
void Adduser(User user)
this._user = user;
这样打电话
userProfile.Adduser(snapshot.data);
问题:
///problem is here and notifylistner
userProfile.user = snapshot.data;
每当我们调用它时,notifylistner() 都会重建小部件
【讨论】:
以上是关于无法将小部件标记为需要构建,因为框架已经在构建小部件的过程中的主要内容,如果未能解决你的问题,请参考以下文章