Dart / flutter:来自initState的字符串数据无法通过setState

时间:2018-04-06 09:48:28

标签: dart flutter

昨天我制作了一个简单的小部件来获取数据以显示一些基本信息,但我注意到当我弹回列表时,数据通常不存在,我只得到我的错误文本。

我认为这是因为这些小部件最初是无状态的,所以我试图将它们转换为有状态,以便在加载页面时重新加载数据。

这是我收集我的小部件数据的方式:

class BasicDogWidget extends StatefulWidget {
  String URL;

  BasicDogWidget(this.URL);

  @override
  createState() => new BasicDogWidgetState(URL);
}

class BasicDogWidgetState extends State<BasicDogWidget> {
  String URL;
  BasicDogWidgetState(this.URL);

  var result;
  var imageLink;
  var dogName;
  var dogType;
  var dogColor;
  var dogGender;
  var dogAge;

  @override
  initState() {
    fetchImageLink(URL).then((result) {
      setState(imageLink = result);
    });

    fetchDogInfo(URL, 'datas-nev').then((result) {
      setState(dogName = result);
    });

    fetchDogInfo(URL, 'datas-tipus').then((result) {
      setState(dogType = result);
    });

    fetchDogInfo(URL, 'datas-szin').then((result) {
      setState(dogColor = result);
    });

    fetchDogInfo(URL, 'datas-nem').then((result) {
      setState(dogGender = result);
    });

    fetchDogInfo(URL, 'datas-kor').then((result) {
      setState(dogAge = result);
    });

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    if (imageLink == null) {
      return new Container();
    }

    if (dogName == null) {
      return new Container();
    }

    if (dogType == null) {
      return new Container();
    }

    if (dogColor == null) {
      return new Container();
    }

    if (dogGender == null) {
      return new Container();
    }

    if (dogAge == null) {
      return new Container();
    }

    return buildBasicWidget(
        imageLink, dogName, dogType, dogColor, dogGender, dogAge, URL);
  }
}

但是,fetchDogInfo收集的数据似乎无法在setState方法中传递,因为它是一个字符串。

E/flutter (12296): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter (12296): type 'String' is not a subtype of type 'VoidCallback' of 'fn' where
E/flutter (12296):   String is from dart:core
E/flutter (12296): 
E/flutter (12296): #0      State.setState (package:flutter/src/widgets/framework.dart:1086)
E/flutter (12296): #1      BasicDogWidgetState.initState.<anonymous closure> (package:osszefogasaszanhuzokert/dog.dart:230)

有没有办法绕过这个问题?

2 个答案:

答案 0 :(得分:1)

您正在执行异步代码

fetchImageLink(URL).then((result) {

这意味着fetchImageLink(URL)最终将返回一个值,然后执行then(...),但此调用是异步的,这意味着它被添加到事件队列中以便稍后执行,并且代码同步继续执行,直到initState然后build结束,直到此同步代码运行完成,然后执行事件队列中的下一个“任务”,这可能是您的then(...)部分fetchImageLink()如果已经完成,则会致电。

但这应该不是问题 您可以检查值是否可用

  @override
  Widget build(BuildContext context) {
    if(imageLink == null) {
      return new Container(); // dummy widget until there is something real to render
    }

    ... // your other build code

答案 1 :(得分:1)

Flutter有FutureBuilder级。它提供了一个小部件,可以完成所有繁重工作以支持异步Future对象。 FutureBuilder的优点是可以直接添加到小部件树中,并且根据连接的当前状态,可以显示相关的UI以指示进度,结果或错误。

示例:

class JokePageState extends State<JokePage> {
  Future<String> response;

  initState() {
    super.initState();
    response = http.read(dadJokeApi, headers: httpHeaders);
  }

  Widget build(BuildContext context) {
    return new Scaffold(
      body: new Center(
        child: new FutureBuilder<String>(
          future: response,
          builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
            switch (snapshot.connectionState) {
              case ConnectionState.none:
                return const Icon(Icons.sync_problem);
              case ConnectionState.waiting:
              case ConnectionState.active:
                return const CircularProgressIndicator();
              case ConnectionState.done:
                final decoded = json.decode(snapshot.data);
                if (decoded['status'] == 200) {
                  return new Text(decoded['joke']);
                } else {
                  return const Icon(Icons.error);
                }
            }
          },
        ),
      ),
    );
  }
}