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

Flutter Fetch API报错:RangeError与类型不匹配问题求助

解决Flutter Fetch API中的地址显示问题

问题描述

  • 无法获取下一个用户的初始默认地址(shipto=0),当地址列表数量较多时频繁出现;
  • 尝试修复后出现类型不匹配错误:type 'string' is not a subtype of type 'int' of 'index'

原代码

主Widget代码

List<Items> _list = [];
List<Items> _search = [];
var loading = false;

Future fetchMos() async {
  setState(() {
    loading = true;
  });
  _list.clear();
  var client = http.Client();
  String mosUrl = '';

  var url = Uri.parse(mosUrl);
  var headers = {
    'Client-Token': '',
  };
  var response = await client.get(url, headers: headers);
  if (response.statusCode == 200) {
    var data = jsonDecode((utf8.decode(response.bodyBytes)))['items'];
    setState(() {
      for (var index in data) {
        _list.add(Items.fromJson(index));
        loading = false;
      }
    });
  }
}

@override
void initState() {
  super.initState();
  fetchMos();
}

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      elevation: 0.0,
    ),
    body: ListView.builder(
      itemBuilder: (context, index) {
        if (_list.length > 0) {
          return _listItem(index);
        } else {
          return Center(child: CircularProgressIndicator());
        }
      },
      itemCount: _list.length,
    ),
  );
}

_listItem方法

_listItem(index) {
  return Card(
    elevation: 3,
    child: Column(
      children: <Widget>[
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.only(left: 5),
              child: Text(
                "${_list[index].name}  ${_list[index].custnum}",
                style: TextStyle(
                    color: Colors.black,
                    fontSize: 18,
                    fontFamily: "supermarket"),
              ),
            ),
            TextButton(
              child: const Text(
                'แก้ไข',
                style: TextStyle(fontFamily: "supermarket", fontSize: 14),
              ),
              onPressed: () {/* ... */},
            ),
          ],
        ),
        Padding(
          padding: const EdgeInsets.all(5),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              Text(
                'bill To / Ship To : ${_list[index].address![index].shipto.toString()}',
                style: TextStyle(
                    color: Colors.black,
                    fontSize: 16,
                    fontFamily: "supermarket"),
              ),
            ],
          ),
        ),
        Padding(
          padding: const EdgeInsets.all(5),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              Text(
                "ที่อยู่ : ${_list[index].address![index].addr1.toString()}",
                style: TextStyle(
                    color: Colors.black,
                    fontSize: 16,
                    fontFamily: "supermarket"),
              ),
            ],
          ),
        ),
      ],
    ),
  );
}

返回的JSON数据

{
 "items": [
   {
    "custnum": "",
    "name": "",
    "address": [
        {
            "shipto": 0,
            "addr1": "",
            "thanon": "",
            "tambon": "",
            "amphur": "",
            "prov_code": "",
            "province": "",
            "zipcode": "",
            "country": "",
            "contact": "",
            "postcode": ""
        },
        {
           "shipto": 1,
            "addr1": "",
            "thanon": "",
            "tambon": "",
            "amphur": "",
            "prov_code": "",
            "province": "",
            "zipcode": "",
            "country": "",
            "contact": "",
            "postcode": ""
        },
        {
            "shipto": 2,
            "addr1": "",
            "thanon": "",
            "tambon": "",
            "amphur": "",
            "prov_code": "",
            "province": "",
            "zipcode": "",
            "country": "",
            "contact": "",
            "postcode": ""
        },
        {
            "shipto": 3,
            "addr1": "",
            "thanon": "",
            "tambon": "",
            "amphur": "",
            "prov_code": "",
            "province": "",
            "zipcode": "",
            "country": "",
            "contact": "",
            "postcode": ""
        }
    ]
},
    {
    "custnum": "",
    "name": "",
    "address": [
        {
            "shipto": 0,
            "addr1": "",
            "thanon": "",
            "tambon": "",
            "amphur": "",
            "prov_code": "",
            "province": "",
            "zipcode": "",
            "country": "",
            "contact": "",
            "postcode": ""
        },
        {
           "shipto": 1,
            "addr1": "",
            "thanon": "",
            "tambon": "",
            "amphur": "",
            "prov_code": "",
            "province": "",
            "zipcode": "",
            "country": "",
            "contact": "",
            "postcode": ""
        },
        {
            "shipto": 2,
            "addr1": "",
            "thanon": "",
            "tambon": "",
            "amphur": "",
            "prov_code": "",
            "province": "",
            "zipcode": "",
            "country": "",
            "contact": "",
            "postcode": ""
        },
        {
            "shipto": 3,
            "addr1": "",
            "thanon": "",
            "tambon": "",
            "amphur": "",
            "prov_code": "",
            "province": "",
            "zipcode": "",
            "country": "",
            "contact": "",
            "postcode": ""
        }
  ]
}

问题根源与修复方案

核心问题

  • 索引混用:_listItem中用同一个index同时访问用户列表和地址列表,导致第二个用户会去取自己的第1个地址(而非默认的第0个),当用户列表的索引超过地址列表长度时,直接触发类型/越界错误。
  • 状态更新不当:fetchMos中每次循环都调用setState,性能低下且可能导致状态异常。

修复后的代码

1. 修正_listItem方法(固定取默认地址+空安全)

Widget _listItem(int index) {
  final user = _list[index];
  // 确保地址列表非空时取第0个默认地址
  final defaultAddress = user.address?.isNotEmpty == true ? user.address![0] : null;
  
  return Card(
    elevation: 3,
    child: Column(
      children: <Widget>[
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.only(left: 5),
              child: Text(
                "${user.name}  ${user.custnum}",
                style: TextStyle(
                    color: Colors.black,
                    fontSize: 18,
                    fontFamily: "supermarket"),
              ),
            ),
            TextButton(
              child: const Text(
                'แก้ไข',
                style: TextStyle(fontFamily: "supermarket", fontSize: 14),
              ),
              onPressed: () {/* ... */},
            ),
          ],
        ),
        // 只有默认地址存在时才显示地址相关内容
        if (defaultAddress != null) ...[
          Padding(
            padding: const EdgeInsets.all(5),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.start,
              children: [
                Text(
                  'bill To / Ship To : ${defaultAddress.shipto.toString()}',
                  style: TextStyle(
                      color: Colors.black,
                      fontSize: 16,
                      fontFamily: "supermarket"),
                ),
              ],
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(5),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                Text(
                  "ที่อยู่ : ${defaultAddress.addr1.toString()}",
                  style: TextStyle(
                      color: Colors.black,
                      fontSize: 16,
                      fontFamily: "supermarket"),
                ),
              ],
            ),
          ),
        ],
      ],
    ),
  );
}

2. 优化fetchMos方法(批量更新状态+错误处理)

Future fetchMos() async {
  setState(() {
    loading = true;
  });
  _list.clear();
  var client = http.Client();
  String mosUrl = '';

  var url = Uri.parse(mosUrl);
  var headers = {
    'Client-Token': '',
  };
  var response = await client.get(url, headers: headers);
  
  setState(() {
    if (response.statusCode == 200) {
      var data = jsonDecode((utf8.decode(response.bodyBytes)))['items'];
      for (var item in data) {
        _list.add(Items.fromJson(item));
      }
    }
    // 无论请求成功失败,都重置loading状态
    loading = false;
  });
}

修复说明

  • 把_list[index].address![index]改为_list[index].address![0],确保每个用户都显示自己的默认地址(shipto=0),解决第一个问题;
  • 添加空安全判断,避免地址列表为空时触发异常;
  • 将loading = false移出循环,仅在所有数据处理完成后更新状态,提升性能;
  • 新增请求失败的状态处理,避免loading一直处于true状态。

内容的提问来源于stack exchange,提问作者Ppnncs

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 07:55:25