无法从Coinmarketcap API获取数据并在Flutter ListView中展示
问题解决:Coinmarketcap API数据无法在Flutter ListView展示
问题描述
尝试从Coinmarketcap API获取数据并在Flutter的ListView中展示,使用Mock API时代码正常运行,但对接真实API时无法成功展示数据。API调用的信用计数在增加,说明请求已发送并被处理,但ListView始终无法渲染数据。
错误原因
查看Postman返回的API响应可知,真实API返回的是单个对象(包含status和data字段),但原代码错误地将响应体解析为List类型,导致解析失败,最终没有数据传递给ListView。
原代码错误点:
final List body = json.decode(response.body); return body.map((e) => CryptoModel.fromJson(e)).toList();
修复步骤
- 调整API请求的返回类型:将
Future<List<CryptoModel>>改为Future<CryptoModel>,因为接口返回单个加密货币数据。 - 修正解析逻辑:从响应体中提取
data字段,传递给CryptoModel.fromJson。 - 更新FutureBuilder:适配单个数据的渲染逻辑,同时添加错误捕获便于调试。
- 确保模型类匹配API结构:补充正确的
CryptoModel及嵌套类定义。
修复后完整代码
1. 模型类定义
class CryptoModel { final int id; final String symbol; final String name; final double amount; final String lastUpdated; final Quote quote; CryptoModel({ required this.id, required this.symbol, required this.name, required this.amount, required this.lastUpdated, required this.quote, }); factory CryptoModel.fromJson(Map<String, dynamic> json) { return CryptoModel( id: json['id'], symbol: json['symbol'], name: json['name'], amount: json['amount'].toDouble(), lastUpdated: json['last_updated'], quote: Quote.fromJson(json['quote']['USD']), ); } } class Quote { final double price; final String lastUpdated; Quote({ required this.price, required this.lastUpdated, }); factory Quote.fromJson(Map<String, dynamic> json) { return Quote( price: json['price'].toDouble(), lastUpdated: json['last_updated'], ); } }
2. API请求函数
import 'dart:convert'; import 'package:http/http.dart' as http; Future<CryptoModel> getCryptoMarket() async { const url = 'https://pro-api.coinmarketcap.com/v2/tools/price-conversion?amount=1&id=1'; var response = await http.get(Uri.parse(url), headers: { 'Accepts': 'application/json', 'X-CMC_PRO_API_KEY': 'YOUR KEY HERE' // 替换为你的API密钥 }); if (response.statusCode == 200) { final Map<String, dynamic> body = json.decode(response.body); return CryptoModel.fromJson(body['data']); } else { throw Exception('请求失败: ${response.statusCode}'); } } Future<CryptoModel> cryptoFuture = getCryptoMarket();
3. 页面渲染代码
import 'package:flutter/material.dart'; void main() { runApp(const DENEME2()); } class DENEME2 extends StatefulWidget { const DENEME2({super.key}); @override State<DENEME2> createState() => _DENEME2State(); } class _DENEME2State extends State<DENEME2> { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: FutureBuilder<CryptoModel>( future: cryptoFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const CircularProgressIndicator(); } else if (snapshot.hasData) { final crypto = snapshot.data!; return buildCryptoItem(crypto); } else if (snapshot.hasError) { return Text('错误: ${snapshot.error}'); // 显示错误信息便于调试 } else { return const Text("无可用数据"); } }, ), ), ), ); } } Widget buildCryptoItem(CryptoModel crypto) { return ListView( children: [ Container( color: Colors.grey.shade300, margin: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5), height: 100, width: double.maxFinite, child: Row( children: [ Expanded(flex: 1, child: Text(crypto.symbol)), const SizedBox(width: 10), Expanded(flex: 3, child: Text(crypto.name)), ], ), ), ], ); }
额外说明
- Mock API正常是因为它返回的是数组结构,与原代码的List解析逻辑匹配,而真实API返回单个对象,因此需要调整解析逻辑。
- 添加错误捕获后,可以直观看到解析或请求过程中出现的问题,便于快速定位。
内容的提问来源于stack exchange,提问作者Efe Bozkurt
相关产品推荐
相关产品推荐

