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

Flutter基于类模型集成API时ListView无法加载列表数据问题排查

Flutter 紧急联系人列表API集成ListView渲染异常排查

核心问题共3处,按影响优先级排序:

  • UI层变量作用域错误:getAllEmergenceyContacts方法内重新定义了局部变量books,接口返回的数据仅存在于方法作用域内,类层级的books列表始终为空,ListView拿不到有效数据。
  • 异步请求后未触发UI刷新:接口请求是异步操作,数据返回后没有调用状态刷新方法,UI不会主动更新渲染列表。
  • 数据模型字段映射错位:fromJson和toJson方法内字段和接口返回值对应关系写反,后续渲染会出现字段值错乱问题。
  • 补充说明:控制台打印[Instance of 'Book', Instance of 'Book']是Dart打印自定义类实例的默认输出,不是数据拉取失败,属于正常现象。

修正后的数据模型Book类

修正字段映射关系,增加空安全兼容,符合Dart命名规范:

class Book {
  final int id;
  final String phone;
  final String name;
  final String relation;
  final String updatedAt;
  final String createdAt;
  final int userId;
  final String? image; // 接口返回image字段,做可空兼容

  Book({
    required this.id,
    required this.name,
    required this.phone,
    required this.relation,
    required this.createdAt,
    this.image,
    required this.updatedAt,
    required this.userId,
  });

  factory Book.fromJson(Map<String, dynamic> json) => Book(
        id: json['id'] as int, // 对应接口返回的联系人主键ID
        name: json['contact_person'] as String, // contact_person为联系人姓名字段
        relation: json['relation'] as String,
        phone: json['phone'] as String,
        updatedAt: json['updated_at'] as String,
        createdAt: json['created_at'] as String,
        userId: json['user_id'] as int, // 对应接口返回的所属用户ID
        image: json['image'] as String?,
      );

  Map<String, dynamic> toJson() => {
        'id': id,
        'user_id': userId,
        'contact_person': name,
        'relation': relation,
        'phone': phone,
        'image': image,
        'created_at': createdAt,
        'updated_at': updatedAt,
      };

  // 可选:重写toString方法方便调试打印实例内容
  @override
  String toString() {
    return 'Book(id: $id, name: $name, phone: $phone, relation: $relation, userId: $userId)';
  }
}

修正后的接口请求方法

简化循环逻辑,增加空值兜底,避免变量重名引发的逻辑错误:

Future<List<Book>> getBook() async {
  List<Book> bookList = [];
  Map<String, String> headers = {
    "Content-type": "application/json",
    'Authorization': 'Bearer $token',
  };
  var url = Uri.parse(ApiPath.getAllEmergenceyContactUrl);
  final response = await http.get(url, headers: headers);
  if (response.statusCode == 200) {
    Map<String, dynamic> resMap = json.decode(response.body);
    // 接口无user字段时返回空数组做兜底
    List<dynamic> userList = resMap["user"] ?? [];
    // 用内置map方法转换替代手写for循环,减少出错概率
    bookList = userList
        .map((item) => Book.fromJson(item as Map<String, dynamic>))
        .toList();
    return bookList;
  } else {
    throw Exception('获取紧急联系人列表失败');
  }
}

修正后的UI层调用逻辑(以StatefulWidget为例)

修复变量作用域问题,增加加载态与空态提示,异步请求完成后主动刷新UI:

// 状态类内定义的全局变量
List<Book> books = [];
bool isLoading = false;

@override
void initState() {
  super.initState();
  // 页面初始化时拉取数据
  getAllEmergenceyContacts();
}

Future<void> getAllEmergenceyContacts() async {
  // 进入加载状态
  setState(() {
    isLoading = true;
  });
  try {
    // 直接给类层级的books变量赋值,不要在方法内重新定义同名变量
    books = await services.getBook();
  } catch (e) {
    debugPrint('拉取联系人失败: $e');
    // 此处可增加toast等错误提示
  } finally {
    // 请求完成后刷新UI
    setState(() {
      isLoading = false;
    });
  }
}

// 页面build方法内的列表示例
@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: const Text('紧急联系人')),
    body: isLoading
        ? const Center(child: CircularProgressIndicator())
        : books.isEmpty
            ? const Center(child: Text('暂无联系人数据'))
            : ListView.builder(
                itemCount: books.length,
                itemBuilder: (context, index) {
                  final item = books[index];
                  return ListTile(
                    title: Text(item.name),
                    subtitle: Text('关系:${item.relation}\n电话:${item.phone}'),
                  );
                },
              ),
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 23:30:37