设置状态内存泄漏

时间:2021-05-12 19:47:35

标签: flutter dart

我是flutter的初学者,我编写了一个从api调用json数据的代码,然后我执行了但执行速度变慢了一点,并且在控制台中我发现了一条错误消息,内容为

E/flutter ( 6908): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: setState() called after dispose(): _PlayersCreationDetailsViewState#559ce(lifecycle state: defunct, not mounted)
E/flutter ( 6908): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
E/flutter ( 6908): The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
E/flutter ( 6908): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
E/flutter ( 6908): #0      State.setState.<anonymous closure> (package:flutter/src/widgets/framework.dart:1208:9)
E/flutter ( 6908): #1      State.setState (package:flutter/src/widgets/framework.dart:1243:6)
E/flutter ( 6908): #2      _PlayersCreationDetailsViewState.getPlayer (package:footyappp/Fantazyy/players_creation_details_view.dart:101:5)
E/flutter ( 6908): <asynchronous suspension>
E/flutter ( 6908): #3      _PlayersCreationDetailsViewState.getClubIds.<anonymous closure> (package:footyappp/Fantazyy/players_creation_details_view.dart:84:14)
E/flutter ( 6908): #4      State.setState (package:flutter/src/widgets/framework.dart:1244:30)
E/flutter ( 6908): #5      _PlayersCreationDetailsViewState.getClubIds (package:footyappp/Fantazyy/players_creation_details_view.dart:73:5)
E/flutter ( 6908): #6      _rootRunUnary (dart:async/zone.dart:1198:47)
E/flutter ( 6908): #7      _CustomZone.runUnary (dart:async/zone.dart:1100:19)
E/flutter ( 6908): #8      _FutureListener.handleValue (dart:async/future_impl.dart:143:18)

这是我试过的代码:

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:footyappp/Fantazyy/Playerrs.dart';
import 'package:footyappp/Fantazyy/club_api.dart';
import 'package:footyappp/Fantazyy/create_team_view.dart';
import 'package:footyappp/Fantazyy/player%20copy.dart';
import 'package:footyappp/Fantazyy/player_lab.dart';
import 'package:footyappp/Key/Key.dart';
import 'package:http/http.dart' as http;

class PlayersCreationDetailsView extends StatefulWidget {

  final List<Playerr> selectedPlayers;
  final int playerIndex;

  const PlayersCreationDetailsView ({
    Key key,
    @required this.selectedPlayers,
    @required this.playerIndex
  })  : super(key: key);

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


class _PlayersCreationDetailsViewState extends State<PlayersCreationDetailsView> {
  bool _sortAsc = false;
  int _sortColumnIndex = 0;
  double _columnWidth  = 40.0;
  double _columnNameWidth  = 60.0;
  double _columnPosWidth  = 80.0;
  PlayersDataSource _playersDataSource;
  List<Playerr> _players = [];
  List<ClubApi> selectedClubs = [];
  List<int> clubIdentifiers = [];
  List<Playerrs> playersjson = [];
  List<Playerr> playersApi = [];
    List<dynamic> playerList ;
   List _table;


  int _rowsPerPage = 20;
   final String apiUrl =
      "https://v3.football.api-sports.io/players?season=2020&league=39";
  
  static const headers = {
    'x-rapidapi-host': "v3.football.api-sports.io",
    //Always make sure to check the api key and the limit of a request in a free api
    'x-rapidapi-key': ApiKey.key
  };

  void _sort<T>(Comparable<T> getField(Playerr p), int columnIndex, bool ascending) {
    _playersDataSource._sort<T>(getField, ascending);
    setState(() {
      _sortColumnIndex = columnIndex;
      _sortAsc = ascending ;
    });
  }


  Future<void> getClubIds() async {
    http.Response response = await http.get(
        "https://v3.football.api-sports.io/teams?season=2020&league=39",
        headers: {'x-rapidapi-host': "v3.football.api-sports.io",
          'x-rapidapi-key': ApiKey.key});
    String body = response.body;
    var data = jsonDecode(body);
    List<dynamic> table = data['response'];

    setState(() {
      selectedClubs = table
          .map((dynamic item) => ClubApi.fromJson(item))
          .toList();

      for(var item in selectedClubs){
         clubIdentifiers.add(item.team.id);
      }

      for(var item in clubIdentifiers){
        print("club id"+item.toString());
        this.getPlayer(item);
      }

    });

  }


  Future<void> getPlayer(int id) async {
    http.Response response = await http.get(
      "https://v3.football.api-sports.io/players?season=2020&league=39&team=$id",
        headers: {'x-rapidapi-host': "v3.football.api-sports.io",
    'x-rapidapi-key': ApiKey.key});
    String body = response.body;
    var data = jsonDecode(body);
    List<dynamic> table = data['response'];

    setState(() {
      playersjson = table
          .map((dynamic item) => Playerrs.fromJson(item))
          .toList();

      for(var item in playersjson){
        String pos = item.statistics[0].games.position.toString().substring(9);
        playersApi.add(Playerr(item.player.id,item.player.firstname, item.player.lastname, pos,
            item.statistics[0].team.name,item.statistics[0].games.rating, item.statistics[0].games.appearences,item.statistics[0].goals.total,
            item.statistics[0].goals.assists,item.statistics[0].goals.conceded,
            item.statistics[0].cards.red, item.statistics[0].cards.yellow));
      }
      print(playersApi.length);
      // for(var item in playersApi){
      //   print("position"+item.position.toString());
      // print(item.position.contains("DEFENDER"));
      // }
      for(var item in playersApi){
        print("position"+item.position.toString());

      }
      if (widget.playerIndex < 2) {
        _players = playersApi.where((player) => player

            .position.contains("GOALKEEPER")).toList();
      } else if (widget.playerIndex < 7) {
        _players = playersApi.where((player) => player.position.contains("DEFENDER")).toList();
      } else if (widget.playerIndex < 12) {
        _players = playersApi.where((player) => player.position.contains("MIDFIELDER")).toList();
      } else {
        _players = playersApi.where((player) => player.position.contains("ATTACKER")).toList();
      }

      print("length of selected"+widget.selectedPlayers.length.toString());
     for(var item in widget.selectedPlayers){
       print("selected"+item.toString());
       if(item == null){
         print("hello");
       }else if(item !=null){
         print(item.playerID.toString());
         _players.removeWhere((player) => player.playerID == item.playerID);
       }
     }
      //  widget.selectedPlayers.forEach((selectedPlayer) =>
      //     _players.removeWhere((player) => (player.playerID == selectedPlayer.playerID) && (selectedPlayer.playerID != null)));
      //  print("length of selected"+widget.selectedPlayers.length.toString());
      //filter out players who are already selected

        // for (Playerr player in widget.selectedPlayers) {
        //   _players.remove(player);
        // }
        _playersDataSource = PlayersDataSource(widget.playerIndex, widget.selectedPlayers, _players, context);

    });

  }

@override
  void initState() {
  super.initState();
  this.getClubIds();
    //filter out players by position

  }

  @override
  Widget build(BuildContext context) {
    print(playersApi.length);

    return  playersApi.length == 0
        ? Container(
      color: Colors.white,
      child: Center(
        child: CircularProgressIndicator(
          valueColor: AlwaysStoppedAnimation<Color>(
            Color(0xFFe70066),
          ),
        ),
      ),
    )
        : WillPopScope(
      onWillPop: () async => false,
      child: Scaffold(
        body: ListView(
          children: <Widget>[
            PaginatedDataTable(
              columnSpacing: 1.0,
              horizontalMargin: 1.0,
              availableRowsPerPage: [10,20,50],
              rowsPerPage: _rowsPerPage,
              onRowsPerPageChanged: (int value) { setState(() { _rowsPerPage = value; }); },
              sortColumnIndex: _sortColumnIndex,
              sortAscending: _sortAsc,
              header: Text("Players"),
              columns: <DataColumn>[
                new DataColumn(
                    label: new Container(width: _columnPosWidth , child: Text("First Name", softWrap: true,)),
                    numeric: true,
                    onSort: (int columnIndex, bool ascending) => _sort<String>((Playerr p) => p.firstName, columnIndex, ascending)
                ),
                new DataColumn(
                    label: new Container(width: _columnPosWidth , child: Text("Last Name", softWrap: true,)),
                    numeric: true,
                    onSort: (int columnIndex, bool ascending) => _sort<String>((Playerr p) => p.lastName, columnIndex, ascending)
                ),
                new DataColumn(
                    label: new Container(width: _columnPosWidth , child: Text("Position", softWrap: true,)),
                    numeric: true,
                    onSort: (int columnIndex, bool ascending) => _sort<String>((Playerr p) => p.position, columnIndex, ascending)
                ),
                  new DataColumn(
                    label: new Container(width: _columnPosWidth , child: new Text("Price")),
                    numeric: true,
                    onSort: (int columnIndex, bool ascending) => _sort<num>((Playerr p) => p.price, columnIndex, ascending)
                ),
                new DataColumn(
                    label: new Container(width: _columnPosWidth , child: Text("Rating", softWrap: true,)),
                    numeric: true,
                    onSort: (int columnIndex, bool ascending) => _sort<String>((Playerr p) => p.rating, columnIndex, ascending)
                ),
               /* new DataColumn(
                    label: new Container(width: _columnWidth , child: new Text("Position")),
                    numeric: true,
                    onSort: (int columnIndex, bool ascending) => _sort<String>((Playerr p) => p.position, columnIndex, ascending)
                ),*/
                new DataColumn(
                    label: new Container(width: _columnPosWidth , child: new Text("Team")),
                    numeric: true,
                    onSort: (int columnIndex, bool ascending) => _sort<String>((Playerr p) => p.team, columnIndex, ascending)
                ),
                
                new DataColumn(
                    label: new Container(width: _columnPosWidth , child: new Text("Apps")),
                    numeric: true,
                    onSort: (int columnIndex, bool ascending) => _sort<num>((Playerr p) => p.appearances, columnIndex, ascending)
                ),
              
               /* new DataColumn(
                    label: new Container(width: _columnWidth , child: new Text("Points")),
                    numeric: true,
                    onSort: (int columnIndex, bool ascending) => _sort<num>((Player p) => p.points, columnIndex, ascending)
                ),
                new DataColumn(
                    label: new Container(width: _columnWidth , child: new Text("Week Points")),
                    numeric: true,
                    onSort: (int columnIndex, bool ascending) => _sort<num>((Player p) => p.pointsWeek, columnIndex, ascending)
                ),*/
               
               /* new DataColumn(
                    label: new Container(width: _columnWidth , child: new Text("Sub Apps")),
                    numeric: true,
                    onSort: (int columnIndex, bool ascending) => _sort<num>((Player p) => p.subAppearances, columnIndex, ascending)
                ),*/
                new DataColumn(
                    label: new Container(width: _columnPosWidth , child: new Text("Goals")),
                    numeric: true,
                    onSort: (int columnIndex, bool ascending) => _sort<num>((Playerr p) => p.goals, columnIndex, ascending)
                ),
                new DataColumn(
                    label: new Container(width: _columnPosWidth , child: new Text("Assists")),
                    numeric: true,
                    onSort: (int columnIndex, bool ascending) => _sort<num>((Playerr p) => p.assists, columnIndex, ascending)
                ),
                
                new DataColumn(
                    label: new Container(width: _columnPosWidth , child: new Text("Clean")),
                    numeric: true,
                    onSort: (int columnIndex, bool ascending) => _sort<num>((Playerr p) => p.cleanSheets, columnIndex, ascending)
                ),
                new DataColumn(
                    label: new Container(width: _columnPosWidth , child: new Text("Yellows")),
                    numeric: true,
                    onSort: (int columnIndex, bool ascending) => _sort<num>((Playerr p) => p.yellowCards, columnIndex, ascending)
                ),
                new DataColumn(
                    label: new Container(width: _columnPosWidth , child: new Text("Reds")),
                    numeric: true,
                    onSort: (int columnIndex, bool ascending) => _sort<num>((Playerr p) => p.redCards, columnIndex, ascending)
                ),
               
              ],
              source: _playersDataSource,
            )
          ],
        )
      )
    );
  }
}

class PlayersDataSource extends DataTableSource {

  PlayersDataSource(this._playerIndex, this._selectedPlayers, this._players, this.context);

  int _playerIndex;
  List<Playerr> _players;
  List<Playerr> _selectedPlayers;

  int _selectedCount = 0;
  var context;
  double _columnWidth  = 40.0;
  double _columnNameWidth  = 60.0;
  double _columnPosWidth  = 80.0;

  void _sort<T>(Comparable<T> getField(Playerr p), bool ascending) {
    _players.sort((Playerr a, Playerr b) {
      if (!ascending) {
        final Playerr c = a;
        a = b;
        b = c;
      }
      final Comparable<T> aValue = getField(a);
      final Comparable<T> bValue = getField(b);
      return Comparable.compare(aValue, bValue);
    });
    notifyListeners();
  }

  DataCell getCell(String text) {
    return DataCell(Container(width: _columnPosWidth, child: Text(text, overflow: TextOverflow.fade, softWrap: false,)));
  }

  


  @override
  DataRow getRow(int index) {
    assert(index >= 0);
    if (index >= _players.length)
      return null;
    final Playerr player = _players[index];
    return DataRow.byIndex(
      onSelectChanged: (bool) {
        _players.removeAt(index);
        _selectedPlayers[_playerIndex] = player;
        Navigator.pushReplacement(context, MaterialPageRoute(builder: (BuildContext context) {return CreateTeamView(players: _players, selectedPlayers: _selectedPlayers,);}));
      },
        index: index,
        cells: <DataCell>[
          getCell(player.firstName),
          getCell(player.lastName),
          getCell(player.position),
         getCell('${player.price}'),
          getCell('${player.rating}'),
         // getCell('${player.isFresher}'),
          getCell('${player.team}'),
          //getCell('${player.points}'),
         // getCell('${player.pointsWeek}'),
          getCell('${player.appearances}'),
         // getCell('${player.subAppearances}'),
          getCell('${player.goals}'),
          getCell('${player.assists}'),
          getCell('${player.cleanSheets}'),
         // getCell('${player.motms}'),
          getCell('${player.yellowCards}'),
          getCell('${player.redCards}'),
        //  getCell('${player.ownGoals}'),
        ]
    );
  }

  @override
  int get rowCount => _players.length;

  @override
  bool get isRowCountApproximate => false;

  @override
  int get selectedRowCount => _selectedCount;


}

所以问题也是具有攻击者位置的玩家列表:并非所有玩家都显示在列表中,可能是因为设置状态或其他原因,

我正在尝试为设置状态和过滤器的这个问题找到解决方案,我打赌这些问题是相关联的

1 个答案:

答案 0 :(得分:0)

您在页面关闭并调用 setState((){}) 后调用 dispose(),您可以使用 mounted 属性,它是一个布尔值并检查 State 对象当前是否在树中,或在换句话说页面在调用 setState((){})

之前仍然处于活动状态
  if(mounted){
      setState((){})
    }