Flutter中解决API自动触发及搜索无法刷新请求问题
问题解决方案
核心问题分析
- 启动时自动调用API:因为你在
initState里直接初始化了futureVideo = fetchVideo(),此时输入框为空,导致空请求。 - 点击搜索不刷新结果:只修改了
isVisible,但没有重新触发API请求并更新futureVideo,所以FutureBuilder不会重新构建。
具体修改步骤
1. 重构API请求函数,传入搜索关键词
把fetchVideo改成接收参数的形式,避免依赖全局控制器,同时增加空输入判断:
Future<Video> fetchVideo(String query) async { if (query.trim().isEmpty) { throw Exception('请输入搜索关键词'); } final response = await http.get(Uri.parse( 'https://youtube.googleapis.com/youtube/v3/search?part=snippet&channelType=any&eventType=completed&maxResults=3&q=$query&safeSearch=none&type=video&videoLicense=any&videoSyndicated=any&videoType=any&key=[my api key]')); if (response.statusCode == 200) { return Video.fromJson(jsonDecode(response.body)); } else { throw Exception('加载视频失败'); } }
2. 修正State类的状态管理
- 将
searchController移到State类内部(避免全局变量导致的状态混乱) - 把
futureVideo改为可空类型,初始不赋值(避免启动时自动请求) - 移除
initState里的futureVideo初始化代码
修改后的State类:
class _AddPageState extends State<AddPage> { final TextEditingController searchController = TextEditingController(); Future<Video>? futureVideo; bool isVisible = false; @override Widget build(BuildContext context) { // ...原build代码 } }
3. 修复搜索按钮的点击逻辑
在按钮的onPressed里,触发API请求并更新futureVideo,同时处理空输入:
onPressed: () { setState(() { final query = searchController.text.trim(); if (query.isNotEmpty) { futureVideo = fetchVideo(query); isVisible = true; } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('请输入搜索内容')), ); isVisible = false; } }); },
4. 增强Video解析的安全性
避免API返回空结果时崩溃,在fromJson里增加空判断:
factory Video.fromJson(Map<String, dynamic> map) { if (map['items'] == null || map['items'].isEmpty) { throw Exception('未找到相关视频'); } final item = map['items'][0]; return Video( title0: item['snippet']['title'], author0: item['snippet']['channelTitle'], thumbnail0: item['snippet']['thumbnails']['medium']['url'], ); }
5. 优化结果展示逻辑(可选)
如果使用FutureBuilder展示结果,其实可以去掉isVisible,直接根据futureVideo是否为null控制显示:
// 替换原来的Visibility组件 if (futureVideo != null) { return FutureBuilder<Video>( future: futureVideo, builder: (context, snapshot) { if (snapshot.hasData) { return Column( children: [ Text(snapshot.data!.title0), Text(snapshot.data!.author0), Image.network(snapshot.data!.thumbnail0), ], ); } else if (snapshot.hasError) { return Text('${snapshot.error}'); } return const CircularProgressIndicator(); }, ); } else { return const SizedBox.shrink(); // 初始状态不显示任何内容 }
关键说明
- 让API请求函数接收参数,而不是依赖外部控制器,使逻辑更清晰、可复用
- 通过
setState更新futureVideo,触发FutureBuilder重新构建,实现结果刷新 - 增加空输入和空结果判断,避免无效请求和崩溃
内容的提问来源于stack exchange,提问作者Phoenyx
相关产品推荐
相关产品推荐

