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<List<PostModel>>
类型的变量,将_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