mafortis
mafortis

Reputation: 7128

Flutter update list items with delay

I have list of items that are loading from database, the problem is each one of this items require to get 1 string loaded from server and I can't find out a way to make that string get updates.

Logic

  1. Show list of locations from database (done)
  2. Show each item current time (the issue)

Screenshot

one

Code Commented

Padding(
    padding: const EdgeInsets.symmetric(vertical: 1.0, horizontal: 4.0),
    child: ListView.builder(
        itemCount: locations.length,
        itemBuilder: (context, index) {
            WorldTime instance = WorldTime(name: locations[index].name, country: locations[index].country, wikipedia: locations[index].wikipedia, location: locations[index].location, flag: locations[index].flag);


            // need to use await but async/await is not allowed under `Widget build(BuildContext context)`
            instance.getTime();
            var time = instance.time;
            return Card(
                child: ListTile(
                    onTap: () {},
                    title: Text('${locations[index].location}'),
                    subtitle: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                        Text(locations[index].country),
                        SizedBox(height: 5.0),
                        Text('$time'), // <-- show updated time (currently only show first load `null` and never gets updated).
                    ],
                    ),
                    leading: CircleAvatar(
                    backgroundImage: AssetImage('assets/${locations[index].flag}'),
                    ),
                ),
                );
        },
    ),
),

PS: Regarding to instance.getTime() in case you doubt that problem might be from there, I need to assure you that instance.getTime() works absolutely fine in all other screens that I have and here is console log screenshot of it in this particular list items which proves the data are loaded but not show in view (it loads after database list because it needs to get time from server).

two

Question

How can I add time into my list items with some sort of delay? (best if be possible to use async/await)

Update

class WorldTime {

  String location; // location name for the UI
  String time; // the time in that location
  String flag; // url to an asset flag icon
  String country;
  String wikipedia;
  String name; // name of the location to get data from server
  bool isDaytime; // true or false if day time or not

  WorldTime({this.location, this.country, this.wikipedia, this.flag, this.name});

  Future<void> getTime() async {
      var apiUrl =  Uri.https('example.com', 'api/timezone', {'name': '$name'});
      // Await the http get response, then decode the json-formatted response.
      var response = await http.get(apiUrl);
      if (response.statusCode == 200) {
        var jsonResponse = convert.jsonDecode(response.body) as Map<String, dynamic>;

        // get properties from data
        DateTime dateTime = DateTime.now().toUtc();
        String offset = jsonResponse['data']['offset'].substring(1, 3);// 07 (hour)
        String positive = jsonResponse['data']['offset'].substring(0, 1); // determine is positive or negative offset

        // create Datetime object
        String now1 = DateFormat('yyyy-MM-dd HH:mm:ss').format(dateTime);
        DateTime now = DateTime.parse(now1);
        if(positive == '+') {
          now = now.add(
              Duration(
                  hours: int.parse(offset),
                  minutes: int.parse(jsonResponse['data']['offset'].substring(4, 6)) // 00 (minutes)
              )
          );
        } else {
          now = now.subtract(
              Duration(
                  hours: int.parse(offset),
                  minutes: int.parse(jsonResponse['data']['offset'].substring(4, 6)) // 00 (minutes)
              )
          );
        }

        print(now); //2021-05-25 09:57:08.000

        // set the time property
        isDaytime = now.hour > 5 && now.hour < 18 ? true : false;
        time = DateFormat.jm().format(now);
      } else {
        print('Request failed with error:  ${response.statusCode}.');
        isDaytime = false;
        time = 'Could not get time data';
      }
  }
}

Upvotes: 0

Views: 519

Answers (1)

Tirth Patel
Tirth Patel

Reputation: 5736

Use FutureBuilder for calling instance.getTime() since it returns a Future. Replace Text('$time') with following:

FutureBuilder(
  future: instance.getTime(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.done && instance.time != null) {
      return Text(instance.time.toString());
    }
    return Text('No Data');
  },
),

Since getTime returns the void & assigns time to WorldTime instance, use instance inside the if condition.

Upvotes: 1

Related Questions