Flutter FutureBuilder 在调用 Rest API(Backend Laravel)时显示数据然后消失

Posted

技术标签:

【中文标题】Flutter FutureBuilder 在调用 Rest API(Backend Laravel)时显示数据然后消失【英文标题】:Flutter FutureBuilder shows data then disappears when calling Rest API (Backend Laravel) 【发布时间】:2021-03-04 15:36:33 【问题描述】:

我正在运行一个带有 laravel 后端的颤振应用程序,但我遇到了一些问题。

问题是 FutureBuilder 显示数据然后它消失了;有时 length==4 然后它变成 0 并在 Scaffold 中显示“无数据”????

刷新代码时也是这样。

PS:我在 localhost 上运行 laravel 并使用真机进行测试。

环境:android Studio、Windows 10、真机

Laravel 项目:https://github.com/brakenseddik/blog_api_laravel

Flutter 项目:https://github.com/brakenseddik/blog_api_flutter

将“包:http/http.dart”导入为 http;

class Repository 
  String _baseUrl = 'http://192.168.1.2:8000/api';
  httpGet(String api) async 
    return await http.get(_baseUrl + '/' + api);
  

这里是主页源代码

 import 'dart:convert';

import 'package:blog_api/models/post_model.dart';
import 'package:blog_api/services/post_service.dart';
import 'package:flutter/material.dart';

class HomeScreen extends StatefulWidget 
  @override
  _HomeScreenState createState() => _HomeScreenState();


class _HomeScreenState extends State<HomeScreen> 
  PostService _postService = PostService();
  List<PostModel> _list = List<PostModel>();

  Future<List<PostModel>> _getPosts() async 
    var result = await _postService.getAllPosts();
    _list = [];
    if (result != null) 
      var blogPosts = json.decode(result.body);
      blogPosts.forEach((post) 
        PostModel model = PostModel();
        setState(() 
          model.title = post['title'];
          model.details = post['details'];
          model.imageUrl = post['featured_image_url'];
          _list.add(model);
        );
      );
    

    return _list;
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
        appBar: AppBar(
          title: Text('Blog App'),
        ),
        body: FutureBuilder(
          future: _getPosts(),
          builder:
              (BuildContext context, AsyncSnapshot<List<PostModel>> snapshot) 
            print('length of list $_list.length');
            _list = snapshot.data;
            if (_list.length == 0) 
              return Center(
                child: Text('No data'),
              );
             else if (!snapshot.hasData) 
              return Center(
                child: CircularProgressIndicator(),
              );
             else 
              return ListView.builder(
                  itemCount: snapshot.data.length,
                  itemBuilder: (context, index) 
                    return Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Card(
                        child: Column(
                          children: [
                            Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: Image.network(
                                snapshot.data[index].imageUrl,
                                height: 150,
                                //  width: double.maxFinite,
                              ),
                            ),
                            Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: Text(
                                snapshot.data[index].title,
                                style: TextStyle(
                                    fontSize: 18, fontWeight: FontWeight.w700),
                              ),
                            ),
                            Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: Text(
                                snapshot.data[index].details.substring(0, 25),
                                style: TextStyle(
                                  fontSize: 16,
                                ),
                              ),
                            ),
                          ],
                        ),
                      ),
                    );
                  );
            
          ,
        ));
  

还有邮政服务

import 'package:blog_api/repository/repository.dart';

class PostService 
  Repository _repository;
  PostService() 
    _repository = Repository();
  
  getAllPosts() async 
    return await _repository.httpGet('get-posts');
  

【问题讨论】:

【参考方案1】:
future: _getPosts(),

不要那样做。这意味着每次调用 build 时,您都会再次查询您的 API

创建一个Future&lt;List&lt;PostModel&gt;&gt; 类型的变量,将_getPosts() 分配给它一次,然后将该变量与您的FutureBuilder 一起使用。

【讨论】:

但是这个也会做同样的事情,你能澄清更多吗! 嗯,显然你也需要听从其他帖子的建议。【参考方案2】:

我认为问题在于您在_getPosts() 中调用setState。这将重建所有内容,并且永远不会回复FutureBuilder。直接运行不带setState的代码:

blogPosts.forEach((post) 
PostModel model = PostModel();
model.title = post['title'];
model.details = post['details'];
model.imageUrl = post['featured_image_url'];
_list.add(model);

FutureBuilder 最初将使用尚无任何数据的快照调用其构建器。一旦它接收到数据,它将再次调用它的构建器。因此,if (_list.length == 0) 将导致 NPE,因为 _list 为空。

我会尝试更改 if 语句的顺序:

if (!snapshot.hasData) 
  return Center(
    child: CircularProgressIndicator(),
  );
 else if (snapshot.data.length == 0) 
  return Center(
    child: Text('No data'),
  );
 else 
  return ListView.builder( 
  //...

【讨论】:

是的,我用 POSTMAN 测试了 API,它工作正常 ════════ 小部件库捕获的异常═══════════════════════════ ══════════════════════════ 构建FutureBuilder>(脏,状态:_FutureBuilderState >#52aac):getter 'length' 在 null 上调用。接收者:null 尝试调用:长度 我看到它在 getPosts 中调用了 setState,但它不应该这样做。更新了答案

以上是关于Flutter FutureBuilder 在调用 Rest API(Backend Laravel)时显示数据然后消失的主要内容,如果未能解决你的问题,请参考以下文章

Flutter FutureBuilder 在调用 Rest API(Backend Laravel)时显示数据然后消失

使用 Mockito 的 FutureBuilder 快照数据为空 - Flutter

如何在 FutureBuilder Flutter 中停止循环 SetState

Flutter 使用 FutureBuilder 检索列表中的数据

Flutter FutureBuilder 返回空数据

Flutter:不清楚 ValueChanged 和 FutureBuilder