草庐IT

android - FutureBuilder 不等待 future 完成

coder 2023-07-23 原文

我正在使用 API 调用来获取数据并在 ListView 中显示。

这是 FutureBuilder 类:

Widget futureBuilder() {
    return FutureBuilder<List<Project>>(
      future: _getProjects(),
      builder: (context, snapshot) {
        debugPrint('Builder');
        switch (snapshot.connectionState) {
          case ConnectionState.none:
          case ConnectionState.waiting:
          default:
            if (snapshot.hasError)
              return new Text('Error: ${snapshot.error}');
            else
              return listWidget(snapshot);
        }
      },
    );
  }
}

问题是,甚至在 _getProjects() 返回结果之前调用 debugPrint('Builder'),因此快照在我的 ListView 小部件中作为 null 传递。

这是 _getProjects() 类:

Future<List<Project>> _getProjects() async {
    List<Project> projects = [];
    String getProjects = "https://api.myjson.com/bins/1g3xpe";
    var response = await http.get(getProjects);
    Iterable list = json.decode(response.body);
    projects = list.map((model) => Project.fromJson(model)).toList();
    debugPrint('Size ' + projects.length.toString());
    return projects;
  }

完整代码如下:

class Projects extends StatefulWidget {
  @override
  ProjectState createState() => new ProjectState();
}

class ProjectState extends State {

   Future<List<Project>> _getProjects() async {
    List<Project> projects = [];
    String getProjects = "https://api.myjson.com/bins/1g3xpe";
    var response = await http.get(getProjects);
    Iterable list = json.decode(response.body);
    projects = list.map((model) => Project.fromJson(model)).toList();
    debugPrint('Size ' + projects.length.toString());
    return projects;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      primary: true,
      appBar: EmptyAppBar(),
      body: Column(
        children: <Widget>[
          headerWidget(),
          futureBuilder()
        ],
      ),
    );
  }

  Widget futureBuilder() {
    return FutureBuilder<List<Project>>(
      future: _getProjects(),
      builder: (context, snapshot) {
        debugPrint('Builder');
        switch (snapshot.connectionState) {
          case ConnectionState.none:
          case ConnectionState.waiting:
          default:
            if (snapshot.hasError)
              return new Text('Error: ${snapshot.error}');
            else
              return listWidget(snapshot);
        }
      },
    );
  }
}



Widget headerWidget() {
  return Container(
    padding: EdgeInsets.all(16.0),
    color: Colors.blueAccent,
    child: Container(
        decoration: ShapeDecoration(
            color: Colors.white,
            shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.all(Radius.circular(25.0)),
                side: BorderSide(color: Colors.white))),
        child: Row(
          children: <Widget>[
            Padding(padding: EdgeInsets.only(left: 12)),
            Icon(Icons.arrow_back, color: Colors.black54),
            Padding(padding: EdgeInsets.only(left: 12)),
            Flexible(
              fit: FlexFit.loose,
              child: searchBar(),
            ),
            Icon(
              Icons.search,
              color: Colors.black54,
            ),
            Padding(padding: EdgeInsets.only(right: 12)),
          ],
        )),
  );
}

Widget searchBar() {
  return Container(
    height: 52,
    alignment: Alignment.centerLeft,
    padding: EdgeInsets.only(left: 12, right: 12),
    child: TextField(
      decoration: new InputDecoration.collapsed(
        border: InputBorder.none,
        filled: false,
        hasFloatingPlaceholder: false,
        hintText: 'Search here',
        hintStyle: TextStyle(color: Colors.black54),
      ),
    ),
  );
}

Widget listWidget(AsyncSnapshot<List<Project>> snapshot) {
  return Scaffold(
      body: ListView.builder(
          itemBuilder: (BuildContext context, int index) {
            listItem(snapshot.data[index]);
          },
          itemCount: snapshot.data.length));
}

Widget listItem(Project project) {
  return Card(
    elevation: 6.0,
    child: Column(
      children: <Widget>[Text('Project ID'), Text('Project Name')],
    ),
  );
}

class EmptyAppBar extends StatelessWidget implements PreferredSizeWidget {
  @override
  Widget build(BuildContext context) {
    return Container();
  }

  @override
  Size get preferredSize => Size(0.0, 0.0);
}

更新: 我对 FutureBuilder 进行了一些更改:

Widget futureBuilder() {
    return FutureBuilder<List<Project>>(
      future: _getProjects(),
      builder: (context, snapshot) {
        debugPrint('Builder');
        switch (snapshot.connectionState) {
          case ConnectionState.done:
            if (snapshot.hasError)
              return new Text('Error: ${snapshot.error}');
            else
              return listWidget(snapshot);
            break;

          default:
            debugPrint("Snapshot " + snapshot.toString());
        }
      },
    );
  }

我现在收到这个错误:

I/flutter ( 4054): _FutureBuilderState<List<Project>>#67dc4):
I/flutter ( 4054): A build function returned null.
I/flutter ( 4054): The offending widget is: FutureBuilder<List<Project>>
I/flutter ( 4054): Build functions must never return null. To return an empty space that causes the building widget to
I/flutter ( 4054): fill available room, return "new Container()". To return an empty space that takes as little room as
I/flutter ( 4054): possible, return "new Container(width: 0.0, height: 0.0)".

默认情况下,SnapShot 返回此快照 AsyncSnapshot>(ConnectionState.waiting, null, null)

最佳答案

您需要检查是否有AsyncSnapshot(快照)返回的数据。 添加这样的 if 语句:

if(snapshot.hasData && !snapshot.hasError) {
//rest of your code
}
else {
//show progress indicator or error...
}

关于android - FutureBuilder 不等待 future 完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56249715/

有关android - FutureBuilder 不等待 future 完成的更多相关文章

  1. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  2. ruby-on-rails - 在 Ruby on Rails 中发送响应之前如何等待多个异步操作完成? - 2

    在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.

  3. Ruby:行 "m = Hash.new {|h,k| h[k] = []}"完成了什么而 "Hash.new"没有完成? - 2

    一边学习thisRailscast我从Rack中看到了以下源代码:defself.middleware@middleware||=beginm=Hash.new{|h,k|h[k]=[]}m["deployment"].concat[[Rack::ContentLength],[Rack::Chunked],logging_middleware]m["development"].concatm["deployment"]+[[Rack::ShowExceptions],[Rack::Lint]]mendend我的问题是关于第三行。什么是传递block{|h,k|h[k]=[]}到Has

  4. ruby-on-rails - 自动完成搜索的 Rails 实现 - 2

    我不确定如何为我的搜索功能添加自动完成表单。"get"do%>nil%>我有一个具有自定义操作的Controllerdefquery@users=Search.user(params[:query])@article=Search.article(params[:query])end模型如下:defself.user(search)ifsearchUser.find(:all,:conditions=>['first_nameLIKE?',"%#{search}%"])elseUser.find(:all)endenddefself.article(search)ifsearchArt

  5. ruby-on-rails - 使用 Rails 5 完成类(class)和模块分配给用户 - 2

    编辑#2这是类(class)ControllerclassCoursesController编辑#1因此,根据下面Jagdeep的回答,我现在完成了以下操作:类(class).rbclassCoursecourse_modules_user.rbclassCourseModulesUsercourses_user.rbclassCoursesUser用户.rbclassUser迁移classCreateCoursesUsers但是,我遇到这样的错误原始问题所以这是previousquestion的延续,然而,这会偏离那个主题,所以这里是一个新的主题。在此之后,我大致得到了我想要开始工作

  6. ruby - 在 Ruby 中禁用 OptionParser 标志的自动完成 - 2

    #!/usr/bin/envrubyrequire'optparse'options={}OptionParser.newdo|opts|opts.on("--languageLANGUAGE",["Ruby","JavaScript"])do|language|options[:language]=languageendend.parse!puts"Language:#{options[:language]}"如果我用./bin/example--languageRu运行它,它将输出:Language:Ruby我想禁用此自动完成/最接近的匹配行为,并在未提供确切名称时引发Option

  7. ruby - 是否可以在 Unicorn master 完成重启时发送通知? - 2

    我在nginx+unicorn后面运行一系列Rails/Sinatra应用程序,零停机部署。我喜欢这个设置,但Unicorn需要一段时间才能完成重新启动,所以我想在完成时发送某种通知。我能在Unicorn文档中找到的唯一回调与workerfork相关,但我认为这些回调对此不起作用。这是我从赏金中寻找的东西:老unicorn主人启动新主人,然后新主人开始它的worker,然后旧主人停止它的worker并让新主人接管。我想在交接完成后执行一些ruby​​代码。理想情况下,我不想为此实现任何复杂的流程监控。如果这是唯一的方法,那就这样吧。但在走那条路之前,我正在寻找更简单的选择。

  8. ruby - 交集完成后,顺序是否保留在数组中? - 2

    当我对两个数组进行交集时,是否可以保证生成的顺序基于第一个数组的顺序?例如,如果我有a=[1,2,3]b=[3,2,1]可以a&b返回[3,2,1],而不是[1,2,3](这是什么我希望)?我在RDoc或Pickaxe的Array文档中找不到任何直接解决这个问题的内容。RubySpec有一个规范,它createsanarraywithelementsinordertheyarefirstencountered,但我是否应该假设YARVRuby会遵守该规范? 最佳答案 看起来这是一项有保证的功能。他们在revision39415中升级

  9. ruby - 这可以在一个正则表达式中完成吗? - 2

    我需要一个正则表达式来匹配一个字符串:只有数字0-9和空格所有数字必须相同应该至少有2位数字应该以数字开头和结尾匹配:11111111111111111111111111没有匹配项:1hasonlyonedigit11111hasspaceattheend11111hasspaceatbeginning12digitsaredifferent11:hasothercharacter我知道每个要求的正则表达式。这样我将使用4个正则表达式测试。我们可以在一个正则表达式中完成吗? 最佳答案 是的,它可以在一个正则表达式中完成:^(\d)(

  10. ruby-on-rails - 用于 Rails 中配置文件完成百分比的 Gem - 2

    我正在寻找一个很好的gem来处理注册工作流程的“完成百分比”管理。基本上,我的应用程序只允许用户使用电子邮件和密码进行注册,然后有一个LinkedIn样式的百分比指示器,该指示器会随着添加生日和性别等字段而增加。是否存在可帮助设置这样的流程的好gem?谢谢! 最佳答案 这是一个非常简单(而且很蹩脚)的解决方案的演示:在您的模型中,创建一个包含要完成的字段的数组,以及一个用于存储当前状态的整数字段,例如:classUserProc.new{|u|u.progress_status这样,每次用户更新其个人资料时,百分比都会更新(仅当低于

随机推荐