Flutter: Refreshing ListView.Builder with GetX

Issue

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,
                    )
                  ],
                )
            )
          ],
        ),
      ),
    );
  }
}

Answered By – Baker

Answer Checked By – David Goodson (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.