如何在Flutter中优化产品API调用,解决加载耗时过长问题?
优化Flutter中产品与价格API调用的方案
当前核心问题是多次独立价格API请求导致整体加载耗时过长,以下是按优先级排序的可落地优化方案:
1. 后端新增批量价格查询接口(最优解)
这是效率最高的优化方式,直接减少HTTP请求数量。建议后端提供批量接口:
- 请求方式:POST
- 接口地址:
https://api.example.com/api/v1/Products/prices - 请求体:
{"productIds": ["id1", "id2", ...], "quantity": 1} - 返回格式:按产品ID映射的价格数据,如
{"id1": {...priceData}, "id2": {...priceData}}
前端改造代码示例:
if (resp.statusCode == 200) { final data = jsonDecode(resp.body) as List; final productItems = data.map((item) => Product.fromJson(item)).toList(); // 批量请求价格 final productIds = productItems.map((p) => p.id).where((id) => id != null).cast<String>().toList(); var priceResp = await oauth2Helper.post( "https://api.example.com/api/v1/Products/prices", body: jsonEncode({"productIds": productIds, "quantity": 1}), ); if (priceResp.statusCode == 200) { final priceMap = jsonDecode(priceResp.body) as Map<String, dynamic>; for (var product in productItems) { if (product.id != null && priceMap.containsKey(product.id)) { product.price = Price.fromJson(priceMap[product.id!]); } } } productList.addAll(productItems); Navigator.push( context, MaterialPageRoute( builder: (context) => ProductsPage(productList: productList, customer: customer)), ); }
2. 前端控制并发请求数(后端无法修改时用)
一次性发起多个请求可能触发后端限流或客户端网络拥堵,可限制同时发起的请求数量:
// 控制并发数的工具函数 Future<void> runWithConcurrency<T>(List<Future<T> Function()> tasks, int concurrency) async { final running = <Future<T>>[]; for (final task in tasks) { running.add(task()); if (running.length >= concurrency) { await Future.any(running); running.removeWhere((f) => f.isCompleted); } } await Future.wait(running); } // 在loadPage中替换原价格加载逻辑 final priceTasks = productItems.map((product) => () => product.loadPrice()).toList(); await runWithConcurrency(priceTasks, 2); // 限制同时发起2个请求
3. 延迟加载价格(提升用户体验)
无需等所有价格加载完成再跳转页面,先展示产品基本信息,价格后续异步加载:
// ProductsPage中的产品列表项组件 class ProductItem extends StatefulWidget { final Product product; const ProductItem({super.key, required this.product}); @override State<ProductItem> createState() => _ProductItemState(); } class _ProductItemState extends State<ProductItem> { @override void initState() { super.initState(); _loadPrice(); } Future<void> _loadPrice() async { await widget.product.loadPrice(); if (mounted) setState(() {}); } @override Widget build(BuildContext context) { return ListTile( title: Text(widget.product.name ?? ''), subtitle: widget.product.price != null ? Text("${widget.product.price!.value}") : const CircularProgressIndicator(size: 16), ); } }
4. 缓存价格数据
对用户可能重复查看的产品,将价格缓存到本地,避免重复请求:
// 修改Product的loadPrice方法 Future<void> loadPrice() async { // 先读取缓存 final cachedPrice = await _getCachedPrice(id!); if (cachedPrice != null) { price = cachedPrice; return; } var resp = await oauth2Helper.get("https://api.example.com/api/v1/Products/${id}/price?quantity=1"); if (resp.statusCode == 200) { final data = jsonDecode(resp.body); price = Price.fromJson(data); // 缓存1小时 await _cachePrice(id!, price!, DateTime.now().add(const Duration(hours: 1))); } else { print("Error loading price for product $id"); } } // 缓存工具方法(基于SharedPreferences) Future<Price?> _getCachedPrice(String productId) async { final prefs = await SharedPreferences.getInstance(); final jsonStr = prefs.getString("price_$productId"); final expireTimeStr = prefs.getString("price_expire_$productId"); if (jsonStr == null || expireTimeStr == null) return null; final expireTime = DateTime.parse(expireTimeStr); if (DateTime.now().isAfter(expireTime)) { prefs.remove("price_$productId"); prefs.remove("price_expire_$productId"); return null; } return Price.fromJson(jsonDecode(jsonStr)); } Future<void> _cachePrice(String productId, Price price, DateTime expireTime) async { final prefs = await SharedPreferences.getInstance(); await prefs.setString("price_$productId", jsonEncode(price.toJson())); await prefs.setString("price_expire_$productId", expireTime.toIso8601String()); }
内容的提问来源于stack exchange,提问作者Xeno
相关产品推荐
相关产品推荐

