无法将小部件标记为需要构建,因为框架已经在构建小部件的过程中

Widget cannot be marked as needing to build because the framework is already in the process of building widgets

我正在尝试实施 Provider,它似乎工作正常,但我收到此消息:

This _DefaultInheritedProviderScope 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: _DefaultInheritedProviderScope value: Instance of 'UserProfile' listening to value The widget which was currently being built when the offending call was made was: FutureBuilder dirty state: _FutureBuilderState#bf6ec When the exception was thrown, this was the stack:

0 Element.markNeedsBuild. (package:flutter/src/widgets/framework.dart:3896:11)

1 Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:3911:6)

2 _InheritedProviderScopeMixin.markNeedsNotifyDependents (package: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) ... The UserProfile

sending notification was: Instance of '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(),
            );
          }
        },
      )
    );
  }
}

这是用户配置文件 class:

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;
  }
}

为什么会出现此错误?我究竟做错了什么?有人可以帮我解决这个问题吗?

您可以复制粘贴下面的运行完整代码,完整代码修复了这个问题
原因:
这一行 userProfile.user = snapshot.data; 导致错误
FutureBuilder为构建数据,接收notifyListeners()

根据Flutter团队的建议,https://github.com/flutter/flutter/issues/16218#issuecomment-403995076
FutureBuilderbuilder 应该只构建小部件,它不应该有任何逻辑。可以任意调用构建器。

解决方案:
在用户情况下,在 getUser() 之后可以直接设置 UserProfile.user
第 1 步:删除 final userProfile = Provider.of<UserProfile>(context);
第 2 步:将 userProfile.user = snapshot.data; 逻辑移动到 futureBuilderfuture

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(),
    );
  }
}

有问题的代码:

if(condition)
{
  ...
  ...
  notifyListners(); // problem
}else{
  await Future....
  ...
  ...
  notifyListners();  //not getting problem here    
}

代码和解决方案:我没有使用 await 这就是为什么会出现错误。所以在使用 notifyListners()

之前,在异步函数中使用 await
if(condition)
{
  ...
  ...
  await Future.delayed(Duration(milliseconds: 1)); // use await 
  notifyListners(); 
}else{
  await Future....
  ...
  ...
  notifyListners();      
}

当我收到此消息时,我发现在作为侦听器的小部件中有一个 notifylisteners() 调用。

我刚刚删除了多余的 notifyListeners() 调用,一切正常。

之前

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;
  }

现在通知模型class:

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() 重建小部件时。