mankowitz
mankowitz

Reputation: 2031

does setState work on objects in dart/flutter?

I have a flutter widget that attempts to solve soduku grids. I have class called SodukuSolver which does all the calculations and provides a List<String> of the current results. I call setState to refresh the list, but it does not update the screen.

Below, I'll try to include as much of the relevant code as I can. Full source is at https://github.com/mankowitz/soduku

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(title: "Soduku solver", home: Soduku());
  }
}

class SodukuState extends State<Soduku> {
  SodukuSolver ss;
  List<String> _list;
  int _changes = 0;
  int _remaining = 81;

  @override
  Widget build(BuildContext context) {

    final String _starting =
        "750943002024005090300020000140089005093050170500360024000070009070400810400198057";
    ss = new SodukuSolver(_starting);
    _list = ss.getList();

    return Scaffold(
      appBar: AppBar(title: Text('Soduku solver'), actions: <Widget>[
        // action button
        IconButton(
          icon: Icon(Icons.directions_walk),
          onPressed: () {
            _iterate();
          },
        ),    
      ]),
      body: _buildGrid(),
    );
  }

  Widget _buildGrid() {
    return Column(children: <Widget>[
      AspectRatio(
        aspectRatio: 1.0,
        child: Container(
          child: GridView.builder(
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 9,
            ),
            itemBuilder: _buildGridItems,
            itemCount: 81,
          ),
        ),
      ),
    ]);
  }

  Widget _buildGridItems(BuildContext context, int index) {
    return GestureDetector(
      child: GridTile(
        child: Container(
          child: Center(
            child: Text(_list[index]),
          ),
        ),
      ),
    );
  }

  void _iterate() {
    setState(() {
      _changes = ss.iterateSoduku();
      _remaining = ss.empties();
      _list = ss.getList();
    });
  }
}

class Soduku extends StatefulWidget {
  @override
  SodukuState createState() => SodukuState();
}

So the problem is that _iterate() is being called, and I can use the debugger to see that the internal state of SodukuSolver is being updated and it is even passing _list correctly, but the grid on screen doesn't update, even though _changes and _remaining do update.

Upvotes: 0

Views: 290

Answers (2)

Jay Mungara
Jay Mungara

Reputation: 7150

Just add your code in the initState() method as following

    @override
      void initState() {
        super.initState();

        final String _starting =
 "750943002024005090300020000140089005093050170500360024000070009070400810400198057";
        ss = new SodukuSolver(_starting);
        _list = ss.getList();
      }

In your case, your list is not getting updated as setState() method will call your SodukuSolver() and ss.getList(); methods every time. because, setSate() ultimately calls build method to render every time.

So adding it inside your initState method will solve your issue. As it is getting called only once when the screen/route initialises.

Upvotes: 1

Mikhail Ponkin
Mikhail Ponkin

Reputation: 2711

You are creating new SodukuSolver with same _starting every time the widget builds and then obtaining _list from it. So you are overriding changes from previous iteration.
Looks like SodukuSolver creation should be performed once. You can override initState in SodukuState and initialise SodukuSolver there or initialise it in the same place where it is declared

Upvotes: 2

Related Questions