設置狀態內存洩漏 (set state memory leak)


問題描述

設置狀態內存洩漏 (set state memory leak)

我是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;


}

所以問題還在於具有位置攻擊者的玩家列表:並非所有人都顯示在列表中,可能是因為設置狀態或其他原因,

p>

我正在嘗試為設置狀態和過濾器的這個問題找到解決方案,我打賭這些問題是相關的


參考解法

方法 1:

You are calling setState((){}) after page is closed and dispose() was called, you can use mounted property which is a boolean and check whether State object is currently in a tree, or in other words page is still active before calling setState((){})

  if(mounted){
      setState((){})
    }

(by Fares Ben SlamaAra Kurghinyan)

參考文件

  1. set state memory leak (CC BY‑SA 2.5/3.0/4.0)

#dart #Flutter






相關問題

如何將數據傳遞給有狀態的小部件 (How to pass data to stateful widget)

顫振無線電值在步進器中沒有改變 (Flutter Radio Value not Changing in Stepper)

如何在顫動中製作響應式播放按鈕? (How to make a responsive play button in flutter?)

如何將數據數組轉換為在顫振/飛鏢中展開或折疊的小部件列表? (How to convert an array of data to a list of widgets with expand or fold in flutter/dart?)

Flutter - 迭代異步/未來列表 (Flutter - iterate over an asynchrous/future list)

使用顫振將圖像作為blob存儲在mysql數據庫中 (Storing image's as blob in mysql database with flutter)

如何在顫動中將視頻播放器浮動在 youtube 等所有頁面上? (How to float a video player over all pages like youtube in flutter?)

無法設置回調函數。錯誤說:“DropDown”必須有一個方法體,因為“ListLayout”不是抽象的 (Unable to set callback function . Error Says: 'DropDown' must have a method body because 'ListLayout' isn't abstract)

Flutter:如何在沒有評級動作的情況下實現評級欄 (Flutter : How to implement rating bar without rating action)

設置狀態內存洩漏 (set state memory leak)

Flutter 視頻播放器不接受自簽名 https 連接 (Flutter video player wont accept self signed https connection)

為什麼有時上下文被替換為下劃線或“_”? (Why sometimes context is being replace as underscore or "_"?)







留言討論