Flutter调用API获取并展示比特币价格遇问题求助
比特币价格API获取与展示问题排查及修复
我尝试从CoinAPI获取比特币价格并展示,但无法正常实现功能,以下是我的代码:
1. PriceScreen 代码
class PriceScreen extends Stateful Widget { const PriceScreen({super.key}); @override State<PriceScreen> createState() => _PriceScreenState(); } class _PriceScreenState extends State<PriceScreen> { String selectedCurrency = 'USD'; GetBitcoin? bitcoinData; void getData() async { try { var data = await BitcoinApi().getBitcoin(); setState(() { bitcoinData = data; }); } catch (e) { print(e); } } @override void initState() { super.initState(); getData(); } DropdownButton androidDropdown() { List<DropdownMenuItem<String>> dropDownPicker = []; for (String currency in currenciesList) { var newItem = DropdownMenuItem( value: currency, child: Text(currency), ); dropDownPicker.add(newItem); } return DropdownButton( value: selectedCurrency, items: dropDownPicker, onChanged: (value) { setState( () { selectedCurrency = value; getData(); }, ); }, ); } CupertinoPicker iOSPicker() { List<Text> cupertinoPicker = []; for (String currency in currenciesList) { cupertinoPicker.add( Text(currency), ); } return CupertinoPicker( itemExtent: 40.0, onSelectedItemChanged: (selectedItem) { // print(selectedItem); }, children: cupertinoPicker, ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('🤑 Coin Ticker'), ), body: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.stretch, children: <Widget>[ Padding( padding: const EdgeInsets.fromLTRB(18.0, 18.0, 18.0, 0), child: Card( color: Colors.lightBlueAccent, elevation: 5.0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0), ), child: Padding( padding: const EdgeInsets.symmetric( vertical: 15.0, horizontal: 28.0), child: Text( '1 BTC = ${bitcoinData?.rate ?? 'Loading.......'} USD', textAlign: TextAlign.center, style: const TextStyle( fontSize: 20.0, color: Colors.white, ), ), ), ), ), Container( height: 150.0, alignment: Alignment.center, padding: const EdgeInsets.only(bottom: 30.0), color: Colors.lightBlue, child: Platform.isIOS ? iOSPicker() : androidDropdown(), ), ], ), ); } }
2. 数据模型
import 'dart:convert'; GetBitcoin getBitcoinFromJson(String str) => GetBitcoin.fromJson(json.decode(str)); String getBitcoinToJson(GetBitcoin data) => json.encode(data.toJson()); class GetBitcoin { GetBitcoin({ required this.assetIdQuote, required this.rate, }); String assetIdQuote; double? rate; factory GetBitcoin.fromJson(Map<String, dynamic> json) => GetBitcoin( assetIdQuote: json["asset_id_quote"], rate: json["rate"]?.toDouble(), ); Map<String, dynamic> toJson() => { "asset_id_quote": assetIdQuote, "rate": rate, }; }
3. API请求类
import 'package:bitcointicker/model/bitcoin.dart'; import 'package:http/http.dart' as http; const apiKey = 'D502A312-BB71-48CB-A47B-8E24D7593FFC'; const baseUrl = 'https://rest.coinapi.io/v1/exchangerate/BTC/USD'; class BitcoinApi{ Future getBitcoin() async { var client = http.Client(); var uri = Uri.parse(baseUrl); var response = await client.get( uri, headers: { 'X-Api-Key': apiKey, }, ); if (response.statusCode == 200) { var json = response.body; return getBitcoinFromJson(json); } } }
问题排查及修复方案
1. API请求未根据选中币种动态修改URL
当前API请求的baseUrl固定为BTC/USD,切换币种时不会更新请求地址,且iOS选择器未实现切换逻辑:
- 修改
BitcoinApi的getBitcoin方法,接收币种参数:
class BitcoinApi{ Future<GetBitcoin> getBitcoin(String currency) async { var client = http.Client(); var uri = Uri.parse('https://rest.coinapi.io/v1/exchangerate/BTC/$currency'); var response = await client.get( uri, headers: { 'X-Api-Key': apiKey, }, ); if (response.statusCode == 200) { return getBitcoinFromJson(response.body); } else { throw Exception('Failed to load data. Status code: ${response.statusCode}'); } } }
- 更新
getData方法,传入选中的币种:
void getData() async { try { var data = await BitcoinApi().getBitcoin(selectedCurrency); setState(() { bitcoinData = data; }); } catch (e) { print(e); } }
- 完善iOS选择器的
onSelectedItemChanged逻辑:
CupertinoPicker iOSPicker() { List<Text> cupertinoPicker = []; for (String currency in currenciesList) { cupertinoPicker.add(Text(currency)); } return CupertinoPicker( itemExtent: 40.0, onSelectedItemChanged: (selectedItem) { setState(() { selectedCurrency = currenciesList[selectedItem]; getData(); }); }, children: cupertinoPicker, ); }
2. API请求方法未指定返回类型
原getBitcoin方法返回Future而非Future<GetBitcoin>,类型不安全,修改后如上,明确返回类型。
3. 展示文本未动态绑定选中币种
当前展示文本固定为USD,需替换为选中的币种:
Text( '1 BTC = ${bitcoinData?.rate ?? 'Loading.......'} $selectedCurrency', textAlign: TextAlign.center, style: const TextStyle( fontSize: 20.0, color: Colors.white, ), )
4. 错误处理不完善
原API请求仅在状态码200时返回数据,其他情况无处理,添加异常抛出,便于捕获错误原因。
内容的提问来源于stack exchange,提问作者Martins
相关产品推荐
相关产品推荐

