Flutter Error: “Widget cannot build because is already in the process of building”

时间秒杀一切 提交于 2019-12-11 11:32:00

问题


I got this error:

I/flutter (29346): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (29346): The following assertion was thrown building MainLogic(dirty, state: _MainLogic#9c794):
I/flutter (29346): setState() or markNeedsBuild() called during build.
I/flutter (29346): This InhWidget widget cannot be marked as needing to build because the framework is already in the
I/flutter (29346): process of building widgets. A widget can be marked as needing to be built during the build phase
I/flutter (29346): only if one of its ancestors is currently building. This exception is allowed because the framework
I/flutter (29346): builds parent widgets before children, which means a dirty descendant will always be built.
I/flutter (29346): Otherwise, the framework might not visit this widget during this build phase.
I/flutter (29346): The widget on which setState() or markNeedsBuild() was called was:
I/flutter (29346):   InhWidget(state: InhState#3aaa8)
I/flutter (29346): The widget which was currently being built when the offending call was made was:
I/flutter (29346):   MainLogic(dirty, state: _MainLogic#9c794)

Before flooding you with code I'd like to explain a bit the logic behind: I'm trying to implement the rules of the game baccarat, to do so I set up an Inherited widget, some stateless widget send the input to an Object stored in the inherited state, according to this object data other widget rebuild themselves.

the last change I made is applying the baccarat "drawing rules", that can make the Object skip an input when required, but when this happens the inherited widget doesn't like it.

I'll post the last part of the code, but if you think that something else is relevant just ask and I'll post it.

thank you in advance for you help

    class MainLogic extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new _MainLogic();
}
class _MainLogic extends State<MainLogic> {
  Widget cardGrid = CardGrid();
  Widget newGame = NewGame();
  Rules rules;
  bool gameOver;
  @override
  void initState(){
    super.initState();
    gameOver = false;
  }
  @override
  Widget build(BuildContext context) {
    final InhState state = InhWidget.of(context);
    rules = new Rules(game:state.game);
    if(gameOver==false && state.game.count>3 && rules.playerExtraCard()==false)
    {state.skip();}
    if(gameOver==false && state.game.count>4 && rules.bankerExtraCard()==false)
    {state.skip();}
    checkGame(state.game.count);
    return Container(child:status(gameOver));
  }
  status(bool _gameOver) {
    Widget whichOne;
    if (_gameOver) {whichOne=newGame;}
    else {whichOne=cardGrid;}
    return whichOne;
  }
  void checkGame(int cards) {
    if (cards >= 6) {
      gameOver = true;
    } else {gameOver = false;}
  }

...

   class Rules {
  final Game game;
  Rules({this.game});
  static Deck deck = new Deck();
  int get p1 => deck.getValue(game.p1);
  int get p2 => deck.getValue(game.p2);
  int get p3 => deck.getValue(game.p3);
  int get b1 => deck.getValue(game.b1);
  int get b2 => deck.getValue(game.b2);
  int get b3 => deck.getValue(game.b3);
  normalize(List<int> input) {
    int normal;
    int initial = 0;
    input.forEach((num e){initial += e;});
    if(initial>9) {normal=initial-10;}
    else {normal=initial;}
    return normal;
  }
  playerExtraCard() {
    bool extraCard;
    int pInit = normalize([p1,p2]);
    int bInit = normalize([b1+b2]);
    if (pInit > 5) {extraCard = false;}
    else if (bInit > 7) {extraCard = false;}
    else {extraCard = true;}
    return extraCard;
  }
  bankerExtraCard() {
    bool extraCard;
    int pInit = normalize([p1,p2]);
    int bInit = normalize([b1+b2]);
    int pWing = normalize([p3]);
    if (pInit>7) {extraCard = false;}
    else if (bInit>6) {extraCard = false;}
    else if (pInit>5 && bInit<6) {extraCard = true;}
    else if (pInit<6 && bInit==6 && pWing<8 && pWing>5) {extraCard = true;}
    else if (pInit<6 && bInit==5 && pWing<8 && pWing>3) {extraCard = true;}
    else if (pInit<6 && bInit==4 && pWing<8 && pWing>1) {extraCard = true;}
    else if (pInit<6 && bInit==3 && pWing==8) {extraCard = true;}
    else if (pInit<6 && bInit<3) {extraCard = true;}
    else {extraCard = false;}
    return extraCard;
  }
}

...

   class InhState extends State<InhWidget> {
  Game game = new Game();
  @override
  void initState() {
    super.initState();
    game.blank();
  }
  void deal(String card) {
    setState(() {
      game.cards[game.count] = card;
      game.count = game.count + 1;
    });
  }
  void restart(){
    setState(() {
      game.blank();
    });
  }
  void skip() {
    setState(() {
      game.count = game.count + 1;
    });
  }
  @override
  Widget build(BuildContext context) {
    return new InhCore(
      data: this,
      child: widget.child,
    );
  }
}

...

   class InhWidget extends StatefulWidget {
  InhWidget({this.child});
  final Widget child;
  @override
  State<StatefulWidget> createState() => InhState();
  static InhState of(BuildContext context) {
    return (context.inheritFromWidgetOfExactType(InhCore) as InhCore).data;
  }
}

回答1:


You call state.skip() in build() and setState() in skip()

  void skip() {
    setState(() {
      game.count = game.count + 1;
    });
  } 

Usually it's a good idea to avoid "business logic" in build().

There shouldn't be a need to calculate all that stuff that you do using InhState in build(). build() can be called very often at various times.

You should rather update the state depending on user interaction events (onTap:, ...) or other event sources like streams or futures that indicate state changes from async operations.



来源:https://stackoverflow.com/questions/53498473/flutter-error-widget-cannot-build-because-is-already-in-the-process-of-buildin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!