Flutter中如何在单个函数内调用两个API获取数据与头像
解决方案:在单个函数中调用两个API获取数据
步骤1:调整数据模型(按需)
先确保DataDetails能存储头像相关信息,新增字段用于保存头像URL或二进制数据的引用:
class DataDetails { final String cardName; final String name; final String address; final String? profileImageUrl; // 存储头像URL,允许为空 DataDetails({ required this.cardName, required this.name, required this.address, this.profileImageUrl, }); factory DataDetails.fromJson(Map<String, dynamic> json) { return DataDetails( cardName: json['cardName'] ?? '', name: json['name'] ?? '', address: json['address'] ?? '', profileImageUrl: json['profileImageUrl'] ?? '', // 若API1返回头像地址可直接用,否则后续填充 ); } }
步骤2:编写同时调用双API的函数
这个函数会先请求API1拿到基础信息,再请求API2获取头像,同时处理API2的请求失败场景:
import 'package:http/http.dart' as http; import 'dart:convert'; Future<DataDetails> getData() async { final userId = 34; String? avatarUrl; // 调用API1获取基础信息 final api1Response = await http.get(Uri.parse("你的API1地址")); if (api1Response.statusCode != 200) { throw Exception('API1请求失败'); } var baseData = DataDetails.fromJson(jsonDecode(api1Response.body)); // 调用API2获取头像,包裹在try-catch里避免请求失败导致整个流程中断 try { final api2Response = await http.get(Uri.parse("你的API2地址?id=$userId")); if (api2Response.statusCode == 200) { // 假设API2返回JSON格式:{"avatarUrl": "https://xxx.com/avatar.jpg"} final avatarJson = jsonDecode(api2Response.body); avatarUrl = avatarJson['avatarUrl'] ?? ''; } else { print('API2请求失败,状态码:${api2Response.statusCode}'); } } catch (e) { print('API2请求出错:$e'); } // 返回合并后的数据 return DataDetails( cardName: baseData.cardName, name: baseData.name, address: baseData.address, profileImageUrl: avatarUrl, ); }
步骤3:更新FutureBuilder与UI展示
替换原来的FileImage为NetworkImage,同时处理头像加载失败或无数据的情况:
FutureBuilder<DataDetails>( future: getData(), builder: (context, snapshot) { // 加载中状态 if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } // 请求出错状态 if (snapshot.hasError) { return Center(child: Text('加载失败:${snapshot.error}')); } // 无数据状态 if (!snapshot.hasData) { return const Center(child: Text('暂无数据')); } final data = snapshot.data!; return Screenshot( controller: _ssController, child: GestureDetector( onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => OntapView())); }, child: Stack( children: [ Container( padding: const EdgeInsets.all(10), width: 350, decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), color: const Color(0xffccf7ff), ), child: Column( children: [ Container( padding: const EdgeInsets.all(10), child: Row( children: [ Container( height: 15, width: 200, child: Text( data.cardName, style: const TextStyle(fontWeight: FontWeight.bold), ), ), ], ), ), const SizedBox(height: 8), Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ CircleAvatar( radius: 45, backgroundColor: Colors.grey, // 有头像URL时用NetworkImage,否则显示默认图标 backgroundImage: data.profileImageUrl?.isNotEmpty == true ? NetworkImage(data.profileImageUrl!) : null, child: data.profileImageUrl?.isEmpty != false ? const Icon(Icons.person, size: 40) : null, ), const SizedBox(width: 10), Container( padding: const EdgeInsets.only(left: 20, top: 10), width: 130, height: 100, child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ Text( data.name, style: const TextStyle( fontSize: 22, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 5), Text( data.address, style: const TextStyle(fontSize: 12), ), ], ), ), ], ), // 补充剩余UI组件 ], ), ), ], ), ), ); }, )
额外说明
- 如果API2返回的是图片二进制数据而非URL,可将响应体转为
MemoryImage使用:final api2Response = await http.get(Uri.parse("你的API2地址?id=$userId")); if (api2Response.statusCode == 200) { final imageBytes = api2Response.bodyBytes; // UI中使用MemoryImage(imageBytes) } - 可根据业务需求优化错误处理逻辑,比如添加重试按钮、自定义错误提示等。
内容的提问来源于stack exchange,提问作者Nihar
相关产品推荐
相关产品推荐

