0

I am calling API data inside Listview. builder in flutter but the error I am facing is the items are changing their positions automatically.

For Example, When I load this class for the First Time the arrangement of List items is the same as required but after 30-40 seconds the List items arrangement automatically starts changing, and data showing itself randomly.

I am looking for someone who can help me to fix this issue?

For this purpose here is myClass Code.

import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart'as HTTP;
import 'package:worldcup/utils/colors.dart';

class SeriesSchedulePage extends StatefulWidget {

@override
 _SeriesSchedulePageState createState() => _SeriesSchedulePageState(); 
  }


class _SeriesSchedulePageState extends State<SeriesSchedulePage> {

List<dynamic> matches = [];
var match;

getSchedule() async {
http.Response response = await http
    .get(Uri.parse("https://api.cricket.com.au/matches/2780"));
    final Map parseData = await json.decode(response.body.toString());
    matches = parseData['matchList']["matches"];
    setState(() {
    match = matches;
    });
    }

    @override
    Widget build(BuildContext context) {
    return Scaffold(
    backgroundColor: AppColors.primaryWhite,
    appBar: AppBar(

    backgroundColor: AppColors.yellow,

    elevation: 0,

    centerTitle: true,

    leading: IconButton(
      onPressed: () {
        Navigator.pop(context,true);
      },
      icon: Icon(
        Icons.arrow_back,
        color: Colors.white,
      ),
    ),

    title: Text(
      'Schedule',
      textScaleFactor: 0.9,
      style: GoogleFonts.openSans(
          color: Colors.white,
          fontWeight: FontWeight.w600,
          fontSize: 17),
    ),

  ),

  body: Container(
    child: FutureBuilder(
      future: getSchedule(),
      builder: (context, snapshot) {
        if (match == null) {
          return Center(
              child: CupertinoActivityIndicator(
                  animating: true, radius: 15));
        } else
          return ListView.builder(
              itemCount: matches.length,
              shrinkWrap: true,
              reverse: false,
              itemBuilder: (context, index) {
                if (matches[index]["status"] =="UPCOMING") {
                  return Card(
                  elevation: 2,
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(7),
                  ),
                  child: Container(
                    width: double.infinity,
                    child: Padding(
                      padding: EdgeInsets.only(left: 15, top: 7, bottom: 7, right: 15),
                      child: Row(
                        children: [
                          SizedBox(width: 20,),
                          Expanded(
                            flex: 2,
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.spaceBetween,
                              children: [
                                Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    Text(
                                      matches[index]['name'].toString(),
                                      textScaleFactor: 0.9,
                                      style: GoogleFonts.openSans(
                                          fontWeight: FontWeight.w700, fontSize: 15),
                                    ),
                                    SizedBox(height: 10,),

                                    Text(
                                      matches[index]["homeTeam"]['name'].toString(),
                                      textScaleFactor: 0.9,
                                      style: GoogleFonts.openSans(
                                          fontWeight: FontWeight.w700, fontSize: 15),
                                    ),
                                    SizedBox(height: 10,),

                                    Text(
                                      matches[index]["awayTeam"]['name'].toString(),
                                      textScaleFactor: 0.9,
                                      style: GoogleFonts.openSans(
                                          fontWeight: FontWeight.w500, fontSize: 13),
                                    ),
                                  ],
                                ),
                              ],
                            ),
                          ),
                        ],
                      ),
                    ),
                  )
                );
                } else {
                  return Center(
                    child: Text("No Upcoming Match in this series"),
                  );
                }
              }
          );
      },
    ),
  )
 );
 }
 }
  • See https://stackoverflow.com/questions/60990519/future-builder-keeps-rebuilding-on-every-setstate – croxx5f Aug 22 '21 at 05:36

1 Answers1

0

The issue is because getSchedule() has a setState inside it. When the build method is called, getSchedule() will trigger, and since it is calling setState , the build method is being called again, causing your widgets to continuously rebuild in an infinite loop.

What you need to do is prevent such a loop from happening. I see that you are using FutureBuilder too, that is a solution but your implementation is incorrect.

What you should do is this:

  Future<List<dynamic>> getSchedule() async {
    http.Response response =
        await http.get(Uri.parse("https://api.cricket.com.au/matches/2780"));
    final Map parseData = await json.decode(response.body.toString());
    var matches = parseData['matchList']["matches"];
    return matches;
  }

This function returns a Future<List<dynamic>> which your future builder can use to handle the builds. For info on future builder here https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html.

Since you FutureBuilder will react to what is provided by getSchedule() when the future is complete, you do not need to use setState to rebuild.

I have modified your SeriesShedualPage here is the full code:

 class SeriesSchedulePage extends StatefulWidget {
  @override
  _SeriesSchedulePageState createState() => _SeriesSchedulePageState();
}

class _SeriesSchedulePageState extends State<SeriesSchedulePage> {
  Future<List<dynamic>> getSchedule() async {
    http.Response response =
        await http.get(Uri.parse("https://api.cricket.com.au/matches/2780"));
    final Map parseData = await json.decode(response.body.toString());
    var matches = parseData['matchList']["matches"];
    return matches;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Container(
      child: FutureBuilder<List<dynamic>>(
        future: getSchedule(),
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            List<dynamic> matches = snapshot.data!;

            return ListView.builder(
                itemCount: matches.length,
                shrinkWrap: true,
                reverse: false,
                itemBuilder: (context, index) {
                  if (matches[index]["status"] == "UPCOMING") {
                    return Card(
                        elevation: 2,
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(7),
                        ),
                        child: Container(
                          width: double.infinity,
                          child: Padding(
                            padding: EdgeInsets.only(
                                left: 15, top: 7, bottom: 7, right: 15),
                            child: Row(
                              children: [
                                SizedBox(
                                  width: 20,
                                ),
                                Expanded(
                                  flex: 2,
                                  child: Row(
                                    mainAxisAlignment:
                                        MainAxisAlignment.spaceBetween,
                                    children: [
                                      Column(
                                        crossAxisAlignment:
                                            CrossAxisAlignment.start,
                                        children: [
                                          Text(
                                            matches[index]['name'].toString(),
                                            textScaleFactor: 0.9,
                                          ),
                                          SizedBox(
                                            height: 10,
                                          ),
                                          Text(
                                            matches[index]["homeTeam"]['name']
                                                .toString(),
                                            textScaleFactor: 0.9,
                                          ),
                                          SizedBox(
                                            height: 10,
                                          ),
                                          Text(
                                            matches[index]["awayTeam"]['name']
                                                .toString(),
                                            textScaleFactor: 0.9,
                                          ),
                                        ],
                                      ),
                                    ],
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ));
                  } else {
                    return Center(
                      child: Text("No Upcoming Match in this series"),
                    );
                  }
                });
          }
          return Center(
              child: CupertinoActivityIndicator(animating: true, radius: 15));
        },
      ),
    ));
  }
}
Mozes Ong
  • 1,204
  • 1
  • 11
  • 20