Vlados
Vlados

Reputation: 151

How to sort data from api?

There are two dropdown button with the list of countries and types of sport. If on them somsething is chosen it is need to show listTile with the leagues on it is chosen to the country and/or sport and if on them nothing is chosen - show all leagues.

But I get:

Dart Error: Unhandled exception: setState () called after dispose (): _SportLigPageState # b5830 (lifecycle state: defunct, not mounted) This is what happens if you see the widget tree (e.g.). This error can occur when a call is made. Dispose () callback. It is necessary to ensure that the object is still in the tree. This can be a memory card if it’s not. To avoid memory leaks, consider dispose ().

Api with leagues: https://www.thesportsdb.com/api/v1/json/1/all_leagues.php:

class LigList extends StatefulWidget {
  @override
  _LigListState createState() => _LigListState();
}

class _LigListState extends State<LigList> {
  String sport;
  String country;
  List data;
  Future<String> getJsonData() async {
    http.Response response;
    if (sport != null) {
      if (country != null) response  = await http
          .get(Uri.encodeFull('https://www.thesportsdb.com/api/v1/json/1/all_leagues.php?c=$sport&s=$country'), headers: {"Accept": "application/json"});
      else  response  = await http
          .get(Uri.encodeFull('https://www.thesportsdb.com/api/v1/json/1/all_leagues.php?c=$sport'), headers: {"Accept": "application/json"});}
    else if (country == null){ response  = await http
        .get(Uri.encodeFull('https://www.thesportsdb.com/api/v1/json/1/all_leagues.php'), headers: {"Accept": "application/json"});}
    else  response  = await http
          .get(Uri.encodeFull('https://www.thesportsdb.com/api/v1/json/1/all_leagues.php?c=$country'), headers: {"Accept": "application/json"});


      var convertDatatoJson = json.decode(response.body);
      data = convertDatatoJson['leagues'];
    return "Success";
  }

  static const menuItems = countriesList;
  final List<DropdownMenuItem<String>> _dropDownItems = menuItems
      .map((String CountruValue) =>
      DropdownMenuItem<String>(
        value: CountruValue,
        child: Text(CountruValue),
      ),
  ).toList();

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(
        child: Column(children: <Widget>[
          FutureBuilder(
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                return DropdownButton(
                  value: country,
                  hint: Text("Choose a countre league of which you want to find"),
                  items:  _dropDownItems,
                  onChanged: (value) {
                    country = value;
                    print(country);
                    setState(() {});
                  },
                );}),
          SizedBox(width: 5),
          FutureBuilder(
              future: _getSports(),
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                return snapshot.hasData
                    ? DropdownButton(
                  value: sport,
                  hint: Text("Choose a sport league of which you want to find"),
                  items: snapshot.data,
                  onChanged: (value) {
                    sport = value;
                    print(sport);
                    setState(() {});
                  },
                )
                    : Padding(
                    padding: EdgeInsets.symmetric(vertical: 20),
                    child: CircularProgressIndicator());
              }),
          Flexible(
              child:FutureBuilder(
                  future: getJsonData(),
                  builder: (BuildContext context, AsyncSnapshot snapshot) {
                    return ListView.separated(
                        itemCount: data == null ? 0 : data.length,
                        itemBuilder: (BuildContext context, int i) {
                          return Container(
                              child: Center(
                                  child: Column(
                                      crossAxisAlignment: CrossAxisAlignment
                                          .stretch,
                                      children: <Widget>[
                                        ListTile(
                                          title: Text(data[i]['strLeague']),
                                          subtitle: Text(
                                              data[i]['strSport']),
                                          onTap: () {
                                            Navigator.push(
                                                context,
                                                new MaterialPageRoute(
                                                    builder: (
                                                        BuildContext context) =>
                                                    new ComandListScreen()
                                                  // (data[i])
                                                ));
                                          },
                                        ),
                                      ]
                                  )
                              )
                          );
                        });
                  }))
        ]),
      ),
    );
  }
}

Any assistance is very much appreciated.

Upvotes: 0

Views: 1574

Answers (1)

Filled Stacks
Filled Stacks

Reputation: 4346

There's a lot of things wrong with your code. The first child in your code is wrapped in a FutureBuilder but you're not using any Future functionality.

 FutureBuilder(
   builder: (BuildContext context, AsyncSnapshot snapshot) {
      return DropdownButton(
        value: country,
        hint: Text("Choose a countre league of which you want to find"),
        items:  _dropDownItems,
        onChanged: (value) {
           country = value;
           print(country);
           setState(() {}); // Remove this line
         },
  );}),

In addition to that you also are calling setState() randomly in your onChanged callback with nothing inside of it. I'd suggest you take that widget out of the FutureBuilder and just use the DropdownButton on it's own.

Then also in this line

itemCount: data == null ? 0 : data.length,

You're using data, which is set in the future that you call there. You might want to read up on how to properly use the FutureBuilder widget. Just return the data object from your _getJsonData() Future because it's always returning "Success" anyway. Return the list you want from the Future and then access it using snapshot.data

And lastly there's literally only one setState call in there so remove it and you'll be fine. My assumption is that there's some additional dispose you're calling or navigating away and the app crashes. Will need a lot more info to figure out, but you'll have to fix the way you use Futures and the Future builder so we can ensure it's not because of latent threads coming back and setting the state once you've left the view you were on.

Upvotes: 1

Related Questions