4
votes

I've build a Custemized List. Now I include a Checkbox and if I would checked or unchecked , the following error was thrown: 'setState() called in constructor'

class Lists extends StatefulWidget{  
     @override
    _List createState() => _List();
}

class _List extends State<Lists> {  
  bool checkedvalue = true;
  @override
Widget build(BuildContext context) {

 return futureBuilder();
}

Widget futureBuilder(){  
  var futureBuilder = new FutureBuilder(
      future: rest.fetchPost(),
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        switch (snapshot.connectionState) {
          case ConnectionState.none:
          case ConnectionState.waiting:
            return new Text('loading...');
          default:
            if (snapshot.hasError)
              return new Text('Error: ${snapshot.error}');
            else                    
                return listBuilder(context, snapshot);            
        }
      }
 );

 return new Scaffold(         
      body: futureBuilder,
    );
}

Widget listBuilder(BuildContext context, AsyncSnapshot snapshot) {  
  List<rest.Status> values = snapshot.data;

  if (values == null || values.length == 0){
    return null;
  }


  int items = values.length;

  return ListView.builder(   
  itemCount: items,
  itemBuilder: (BuildContext context, int index) {
    String statusText;
    Image image ;
    Uint8List bytes;

    if(statusList.globalStatus != null){
      for(int i=0;i< statusList.globalStatus.length; i++){
        if(values[index].statusID == statusList.globalStatus[i].id){

            if(statusList.globalStatus[i].kurzform != null){
              statusText = statusList.globalStatus[i].kurzform;
            }else{
              statusText = statusList.globalStatus[i].kurzform;
            }

            if (statusList.globalStatus[i].icon != null){
              bytes = base64Decode(statusList.globalStatus[i].icon);
              image = new Image.memory(bytes) ;
            } 
        }

        if(image== null || statusText == null){            
          statusText= 'Kein Status';
          image=  new Image.asset('assets/null.png');
        }              
      }
    }   
    return new Container( 
      decoration: new BoxDecoration(
          border: Border(top: BorderSide(
          color: Colors.black26,
          width: 1
          )
        )
      ), 


      child:Column(
        children: <Widget>[
          CustomListItemTwo( 
            statusText: statusText,                               
            status:image,
            materialNR: values[index].uArtText,          
            material: values[index].untersuchungsMaterialName,
            probenArt:  values[index].probenart,
            eingansdatum: values[index].eingangsdatumText,
            patient: values[index].vorname + ' ' + values[index].nachname ,
            geburtsdatum: values[index].geburtstagText ,

          ),
          Checkbox(            
              value: checkedvalue ,           
              onChanged: (bool newValue) =>                
                setState(() {
                  checkedvalue = newValue; 
                })              
            ),
        ] 
      ),
    );
  }       
  );
}

}

I/flutter ( 5067): ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════ I/flutter ( 5067): The following assertion was thrown while handling a gesture: I/flutter ( 5067): setState() called in constructor: _List#9044e(lifecycle state: created, no widget, not mounted) I/flutter ( 5067): This happens when you call setState() on a State object for a widget that hasn't been inserted into I/flutter ( 5067): the widget tree yet. It is not necessary to call setState() in the constructor, since the state is I/flutter ( 5067): already assumed to be dirty when it is initially created.

1
please accept the answer if it solved your problem, so the question will not remain as unanswered :)Leonard Arnold

1 Answers

4
votes

My code below is not testet.

There is somewhat a concept error in your code. You should NOT fetch anything inside your build method!

If you put a print e.g. "building..." in your build-method (as I did below) you will see why. The build method is called more than you might think. So you are calling a WebService or whatever more then once, the response will come more then once. Actually the setState() method will trigger a build.

If you want to pull something at the beginning use the initState() method. This method will be called once when the state was created. Use Variables for the state of the call and react to it in the build Method (as said before setState() will trigger a rebuild).

I refactored your code a bit, having this concept in mind, your switch/checkbox problem probably will be gone.

Also please take a look how to use Futures https://api.flutter.dev/flutter/dart-async/Future-class.html

class Lists extends StatefulWidget {
  @override
  _List createState() => _List();
}

class _List extends State<Lists> {
  bool checkedvalue = true;
  bool loading = true;
  AsyncSnapshot asyncSnapshot = null;

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

  @override
  Widget build(BuildContext context) {
    print("building...");
    if(asyncSnapshot != null && asyncSnapshot.hasError){
      return Text("Error : ${asyncSnapshot.error}");
    }
    return (loading) ? Text("LOADING") : listBuilder(context, asyncSnapshot);
  }

  void futureBuilder() async {
    rest.fetchPost().then((snapshot) {
      switch (snapshot.connectionState) {
        case ConnectionState.none:
        case ConnectionState.waiting:
          setState(() {
            loading = true;
          });
          break;
        default:
          if (snapshot.hasError) {
            setState(() {
              loading = false;
            });
          } else {
            setState(() {
              loading = false;
              asyncSnapshot = snapshot;
            });
          }
      }
    });
  }
  .....