Fluter setState()使循环始终被调用

时间:2018-08-29 06:36:03

标签: dart flutter

我下面有这样的代码,简单的流程是我从对象列表中进行循环以创建一些小部件。

class ScoringAttribute {
  int _id;
  bool _isdelete;
  double _scorehigh, _scorelow, _scorevalue;
  String _name, _scoretype, _description, _title;
}

class HomePageState extends State<HomePage> with TickerProviderStateMixin {
  List dataScoringAttributes;
  List<ScoringAttribute> listScoringAttributeObjects = new List<ScoringAttribute>();

  final String urlPresentation = ".../.resentations/getPresentations";
  final String urlScoringAttribute = ".../.scoringattributes/getScoringattributes";

  Future<String> getPresentationData() async {
    var responseScoringAttribute = await http.get(
      Uri.encodeFull(urlScoringAttribute),
      headers: {"Accept": "application/json"}
    );

    var scoringAttributeJson = json.decode(responseScoringAttribute.body);

    dataScoringAttributes = scoringAttributeJson['scoringattributes'];

    for(int i = 0; i < dataScoringAttributes.length; i++) {
      var scoringAttributeObject = new ScoringAttribute();

      scoringAttributeObject._id = dataScoringAttributes[i]["id"];
      scoringAttributeObject._description = dataScoringAttributes[i]["iddescription"];
      scoringAttributeObject._isdelete = dataScoringAttributes[i]["isdelete"];
      scoringAttributeObject._name = dataScoringAttributes[i]["name"];
      scoringAttributeObject._scorehigh = double.parse(dataScoringAttributes[i]["scorehigh"].toString());
      scoringAttributeObject._scorelow = double.parse(dataScoringAttributes[i]["scorelow"].toString());
      scoringAttributeObject._scoretype = dataScoringAttributes[i]["scoretype"];
      scoringAttributeObject._title = dataScoringAttributes[i]["title"];
      scoringAttributeObject._scorevalue = double.parse(dataScoringAttributes[i]["scorelow"].toString());

      listScoringAttributeObjects.add(scoringAttributeObject);
    }

    return "Success";
  }

  List<Widget> scoringAttributeList() {
    List<Widget> list = new List();
    for(int i = 0; i < listScoringAttributeObjects.length; i++) {
      if(listScoringAttributeObjects[i]._scoretype == "slider") {
        list.add(
          new Container(
            child: new Column(
              children: <Widget>[
                new Column(
                  children: <Widget>[
                    //THE SLIDER VALUE TEXT
                    new Text(
                      //CONVERT DOUBLE TYPE TO STRING WITHOUT DECIMAL POINTS
                      listScoringAttributeObjects[i]._scorevalue.toStringAsFixed(listScoringAttributeObjects[i]._scorevalue.truncateToDouble() == listScoringAttributeObjects[i]._scorevalue ? 0 : 0),
                      style: new TextStyle(
                        fontSize: 28.0,
                      ),
                    ),
                    //THE SLIDER
                    new Slider(
                      activeColor: Colors.blueAccent,
                      inactiveColor: const Color(0xFFb7d2e0),
                      min: double.parse(listScoringAttributeObjects[i]._scorelow.toString()),
                      max: double.parse(listScoringAttributeObjects[i]._scorehigh.toString()),
                      value: double.parse(listScoringAttributeObjects[i]._scorevalue.toString()),
                      onChanged: (double value) {
                        setState(() {
                          listScoringAttributeObjects[i]._scorevalue = double.parse(value.round().toString());
                        });
                      },
                    ),
                  ],
                ),
              ],
            ),
          ),
        );
      }
      else if(listScoringAttributeObjects[i]._scoretype == "text_field") {
        list.add(...);
      }
      else if(listScoringAttributeObjects[i]._scoretype == "stars") {
        list.add(...);
      }
      else if(listScoringAttributeObjects[i]._scoretype == "thumb") {
        list.add(new Container(...);
      }
    }

    return list;
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: FutureBuilder<String> (
        future: getPresentationData(),
        builder: (context, snapshot) {
          if(snapshot.hasData) {
            return new Column(
              children: <Widget>[
                new Column(
                  children: scoringAttributeList(),
                ),
              ],
            ),
          }
        },
      ),
    );
  }
}

取决于类型,有一些不同的窗口小部件,并且有4种类型,其中1种类型可能包含1个以上的窗口小部件,因此我使循环取决于iIgot从数据库获取的数据。

问题是我不知道为什么每次在循环中使用setState()时,它总是再次处理该循环,因此创建新的小部件将是一个无限循环,并且将复制窗口小部件(仅在调用setState()时发生)。

例如:列表中有4个数据,如果调用setState(),它将显示8个数据(显示前4个数据两次)

这是示例如何将State()设置到列表中的数据中的例子

onChanged: (double value) {
    setState(() {
      listScoringAttributeObjects[i]._scorevalue = double.parse(value.round().toString());
    });
},

我认为问题是因为我setState()进入了列表内的一些数据。因此,当List状态更改时,它将重新呈现与List相关的任何内容。

是真的吗?

如果是,还有其他解决方案如何更改我的代码? 如果没有,那么我的代码或逻辑中是否有任何错误?

谢谢。真的很期待有关此问题的解决方案,因为我确实陷入了困境,并且已经过去了一个星期:(

2 个答案:

答案 0 :(得分:0)

我看不出这与您代码中的一个setState()有什么关系。仅在使用滑块时才调用它。

我认为问题是由list.add(...)引起的;在scoringAttributeList()中。在执行build()时,您不应修改数据。

您应该假设build()可以随时被重复调用。 构建您的代码,以使其在发生时不会引起问题。

答案 1 :(得分:0)

只需将getPresentationData()移到状态变量。这样它只会一次获得triggered

class HomePageState extends State<HomePage> with TickerProviderStateMixin {
  Future<String> _presentationFuture;

  initState() {
   _presentationFuture = getPresentationData()
  }
//other contents

@override
Widget build(BuildContext context) {
 return new Scaffold(
  body: FutureBuilder<String> (
    future: _presentationFuture,
    builder: (context, snapshot) {
      if(snapshot.hasData) {

重复的原因:我们可以在Slider dataChange上调用setState,它将重新呈现HomePageState,这将再次触发network调用({{ 1}})

注意:如果要在更改滑块时触发网络,请在拨打网络电话之前清除列表

getPresentationData()