You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 17:47:13