Search code examples
flutterflutter-getx

Flutter: Refreshing ListView.Builder with GetX


I am creating the List of Cards according to the number of toDoId.

toDoController.toDo() is like

toDo = [q1, r4, g4, d4].obs;

And, this is my ListView.builder()

  Obx(() {
         List _todo = toDoController.toDo();

         return ListView.builder(
         shrinkWrap: true,
         scrollDirection: Axis.horizontal,
         itemCount: _todo.length,
         itemBuilder: (BuildContext context, int i) {
                           
         var _loading = true;
         var _title = 'loading';
                          
         getTodoInfo() async {
         _title = await toDoController
                .getTodoInfo(
                     _todo[i]
                 );
         _loading = false;
         print(_title); // 'Clean!' <--- returns correct title
         }

         getTodoInfo();

         return Container(
           height: 150,
           width: 150,
           child: _loading
           ? Text(
             _title,
             )
             : Text(
             _title,
             ),
     );
    },
   );
  })

I am trying to make each Container calls the http requests to get the title from my database. Get the title and then update to the Text() widget below. However, it doesn't get updated after the value has been returned from the server.

I could make them wait for the request to get the title by using FutureBuilder. I tried with FutureBuilder too. However, FutureBuilder was not also reactive to the variable changes. So, I am trying to do this here. I kinda get the problem. After, the widget is returned, it is not changeable? Is there any way that I can do it with GetX?


Solution

  • Here's an example of using GetX with a Listview.builder.

    This example uses a GetBuilder rather than Obx, as I'm not sure using a stream adds anything of benefit. If for some reason observables/streams are needed, numbers can be updated to be an .obs and the update() calls should be removed and GetBuilder replaced by GetX or Obx. If someone asks, I'll add that as an alternate example.

    The GetBuilder wraps the ListView.builder and only the ListView will be rebuilt, not the entire widget tree / page.

    import 'package:flutter/material.dart';
    import 'package:get/get.dart';
    
    class ListDataX extends GetxController {
      List<int> numbers = List<int>.from([0,1,2,3]);
    
      void httpCall() async {
        await Future.delayed(Duration(seconds: 1), 
                () => numbers.add(numbers.last + 1)
        );
        update();
      }
    
      void reset() {
        numbers = numbers.sublist(0, 3);
        update();
      }
    }
    
    class GetXListviewPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        ListDataX dx = Get.put(ListDataX());
        print('Page ** rebuilt');
        return Scaffold(
          body: SafeArea(
            child: Column(
              children: [
                Expanded(
                  flex: 8,
                  child: GetBuilder<ListDataX>(
                    builder: (_dx) => ListView.builder(
                        itemCount: _dx.numbers.length,
                        itemBuilder: (context, index) {
                          return ListTile(
                            title: Text('Number: ${_dx.numbers[index]}'),
                          );
                        }),
                  ),
                ),
                Expanded(
                  flex: 1,
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      children: [
                        RaisedButton(
                          child: Text('Http Request'),
                          onPressed: dx.httpCall,
                        ),
                        RaisedButton(
                          child: Text('Reset'),
                          onPressed: dx.reset,
                        )
                      ],
                    )
                )
              ],
            ),
          ),
        );
      }
    }
    

    Obx / Streams version

    Here's the above solution using Rx streams & Obx widget.

    class ListDataX2 extends GetxController {
      RxList<int> numbers = List<int>.from([0,1,2,3]).obs;
    
      void httpCall() async {
        await Future.delayed(Duration(seconds: 1),
                () => numbers.add(numbers.last + 1)
        );
        //update();
      }
    
      void reset() {
        numbers = numbers.sublist(0, 3);
        //update();
      }
    }
    
    
    class GetXListviewPage2 extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        ListDataX2 dx = Get.put(ListDataX2());
        print('Page ** rebuilt');
        return Scaffold(
          body: SafeArea(
            child: Column(
              children: [
                Expanded(
                  flex: 8,
                  child: Obx(
                    () => ListView.builder(
                        itemCount: dx.numbers.length,
                        itemBuilder: (context, index) {
                          return ListTile(
                            title: Text('Number: ${dx.numbers[index]}'),
                          );
                        }),
                  ),
                ),
                Expanded(
                    flex: 1,
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      children: [
                        RaisedButton(
                          child: Text('Http Request'),
                          onPressed: dx.httpCall,
                        ),
                        RaisedButton(
                          child: Text('Reset'),
                          onPressed: dx.reset,
                        )
                      ],
                    )
                )
              ],
            ),
          ),
        );
      }
    }