Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter listview not updating after data update

I have a ListView inside a bottomSheet, that is built using an array of elements. Currently I have one item in there "empty" which is then .clear()ed and populated after an async DB call.

The variable update is correct, and I try to use setState((){}) but the ListView isn't updated at all. I need to close the bottomSheet, reopen it, and the ListView then has the correct items.

Do I need to just call setState or does the bottomSheet builder need to be flagged to update?

Main ListView section:

 @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('My Map'),
          backgroundColor: Colors.green[700],
        ),

        //Put in a stack widget so can layer other widgets on top of map widget
        body: Stack(
          children: <Widget>[
            GoogleMap(
              mapType: _currentMapType,
              markers: _markers,
              onMapCreated: _onMapCreated,
              onCameraMove: _onCameraMove,
              initialCameraPosition: CameraPosition(
                target: _center,
                zoom: 11.0,
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(16.0),
              child: Align(
                  alignment: Alignment.bottomCenter,
                  child: Row(mainAxisSize: MainAxisSize.min, children: <Widget>[
                    SizedBox(width: 16.0),

                    Builder(
                      builder: (context) => FloatingActionButton(   
                          ...
                      ),

                    ),

                    SizedBox(width: 16.0),

                    FloatingActionButton(
                      ...
                    ),

                    SizedBox(width: 16.0),

                    Builder(
                      builder: (context) => FloatingActionButton(
                          child: Icon(Icons.file_download, size: 36.0),
                          backgroundColor: Colors.green,
                          onPressed: () {
                            showBottomSheet(
                                context: context,
                                builder: (context) {
                                  return ListView(
                                    padding: EdgeInsets.all(15.0),
                                    children: <Widget>[

                                         ...

                                      Divider(),

                                      ListTile(
                                        title: Text("Remote JSON Download"),
                                        trailing:
                                        Icon(Icons.refresh),
                                        selected: true,
                                        onTap: _OnPressedReloadJSON,               <-------------
                                      ),

                                      Divider(),

                                      Container(
                                        height: 150.0,
                                        child: ListView.builder(               <-------------
                                          scrollDirection: Axis.horizontal,

                                          itemCount : testList.length, 
                                          itemBuilder: (BuildContext context, int index) {
                                              return Container(
                                                padding: EdgeInsets.all(5.0),
                                                margin: EdgeInsets.all(5.0),
                                                width: 150.0,
                                                color: Colors.red,
                                                child: Text(testList[index]),
                                              );
                                          },

                                        ),
                                      ),

Async Get:

class _MyAppState extends State<MyApp> {

  ...

  _OnPressedReloadJSON() {
    fetchJSONAndMakeListTile();
  }

  ...

  List<String> testList= ["empty"];

  Future<http.Response> fetchJSONAndMakeListTile() async {
    final response = await http.get('https://..... file.json');

    // If the server did return a 200 OK response, then parse the JSON.
    if (response.statusCode == 200) {
      List<db_manager.MyObject> myObjects = (json.decode(response.body) as List)
          .map((e) => db_manager.MyObject.fromJson(e))
          .toList();

      testList.clear();
      myObjects.forEach((db_manager.MyObject al) {
        testList.add(al.code);
        print("debug:"+al.code+" - "+al.name);        <------------- prints correctly
      });

      //TODO Does this even work?
      //Trigger update of state - ie redraw/reload UI elements
      setState(() {});

    } else {
      // If the server did not return a 200 OK response, then throw an exception.
      print(response);
      throw Exception('Failed to load json');
    }
  }

UPDATE:

I've abstracted the BottomSheet builder into another class (as per another answer) as its own StatefulWidget but I can't seem to access the void onPress() method from my main dart file. If the BottomSheet creation/builder is in this separate dart file, how do I call it to build and then update its state with the async call updating the listview contents List?

BottomSheetWidget.dart

class BottomSheetDatabases extends StatefulWidget {
  @override
  _BottomSheetDatabases createState() => _BottomSheetDatabases();
}

class _BottomSheetDatabases extends State<BottomSheetDatabases> {

  void _onpress() {

  }

  void loadMe() {

  }

  List<String> testList= ["empty"];

  @override
  Widget build(BuildContext context) {
    return BottomSheet(

        builder: (context) {
          return ListView(
            padding: EdgeInsets.all(15.0),
            children: <Widget>[
              ListTile(
                ...

              ),

              Divider(),

              Container(
                height: 150.0,
                child: ListView.builder(
                  scrollDirection: Axis.horizontal,

                  itemCount: testList.length,
                  itemBuilder: (BuildContext context, int index) {
                    return Container(
                      key: UniqueKey(),
                      //TODO  ??
                      padding: EdgeInsets.all(5.0),
                      margin: EdgeInsets.all(5.0),
                      width: 150.0,
                      color: Colors.red,
                      child: Text(testList[index]),
                    );
                  },

                ),
                //),
                //),
              ),

              ...

Main.dart:

  void _loadSheetDatabases() {
    BottomSheetWidget bottomSheetwidget = BottomSheetWidget();
    bottomSheetwidget.loadMe();
  }
like image 838
Jammo Avatar asked Feb 19 '20 16:02

Jammo


1 Answers

Seems to me that a Key are missing into widget that ListView.Builder returns, try to put a UniqueKey() or ValueKey into Container or Text:

Container(
   key: UniqueKey(),
   padding: EdgeInsets.all(5.0),
   margin: EdgeInsets.all(5.0),
   width: 150.0,
   color: Colors.red,
   child: Text(testList[index]),
);
like image 172
Renê Guilherme Nucci Avatar answered Sep 20 '22 06:09

Renê Guilherme Nucci