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

Dart/Flutter中移除嵌套值为空的列表元素及多嵌套处理

解决联系人同步Firebase的空值报错与多字段处理问题

问题根源分析

  1. 过滤逻辑无效:原代码里直接调用contact.phones?.first,当phones是空列表时会直接抛出Bad state: No element错误,根本走不到判断逻辑;而且最后映射数据时用的是原contacts列表,不是过滤后的result,等于白做了过滤。
  2. 空字段未安全处理:直接访问k.phones?.first.value或写错的k.email?.value(注意contacts_service中邮箱是emails列表),当列表为空时会触发错误。
  3. 重复代码冗余:电话和邮箱的格式化逻辑重复,没有复用。

正确解决方案

步骤1:修复过滤逻辑(可选)

如果想保留所有联系人(哪怕无电话/邮箱),可以跳过过滤直接在映射时处理空值;如果只想保留有有效联系方式的联系人,过滤条件要判断列表是否非空:

List<Contact> filteredContacts = contacts.where((contact) {
  // 保留有电话或邮箱的联系人
  return (contact.phones?.isNotEmpty == true) || (contact.emails?.isNotEmpty == true);
}).toList();

步骤2:安全处理嵌套字段 + 复用格式化逻辑

提取通用格式化函数,对每个字段做空安全判断,避免直接访问列表的first元素:

// 通用格式化函数:处理空值,移除空格和特殊字符
String? formatContactField(String? value) {
  if (value == null || value.trim().isEmpty) return null;
  return value
      .replaceAll(RegExp(r"\s\b|\b\s"), "")
      .replaceAll(RegExp(r'[^\w\s]+'), '');
}

完整修改后的代码

import '../../backend/backend.dart';
import '../../flutter_flow/flutter_flow_theme.dart';
import '../../flutter_flow/flutter_flow_util.dart';
import 'index.dart';
import 'package:flutter/material.dart';
import 'package:contacts_service/contacts_service.dart';

// 通用格式化函数:处理空值并清理特殊字符
String? formatContactField(String? value) {
  if (value == null || value.trim().isEmpty) return null;
  return value
      .replaceAll(RegExp(r"\s\b|\b\s"), "")
      .replaceAll(RegExp(r'[^\w\s]+'), '');
}

Future syncContactstoFirebase(String? userID) async {
  if (userID == null) {
    print("User ID is null, aborting sync");
    return;
  }

  List<Contact> contacts = await ContactsService.getContacts();
  
  // 可选:过滤掉没有电话和邮箱的联系人
  List<Contact> filteredContacts = contacts.where((contact) {
    return (contact.phones?.isNotEmpty == true) || (contact.emails?.isNotEmpty == true);
  }).toList();

  final instance = FirebaseFirestore.instance;
  CollectionReference collection =
      instance.collection('users').doc(userID).collection('contacts');

  Map<String, dynamic> data = {
    'contacts': filteredContacts
        .map((k) => {
              'name': k.displayName ?? '未知名称', // 给空名称设置默认值
              'phone': formatContactField(k.phones?.isNotEmpty == true ? k.phones!.first.value : null),
              'email': formatContactField(k.emails?.isNotEmpty == true ? k.emails!.first.value : null),
            })
        .toList(),
  };

  return collection
      .doc()
      .set(data)
      .then((value) => print("Contacts Updated"))
      .catchError((error) => print("Failed to update Contacts: $error"));
}

关键修改点说明

  • 空安全判断:所有访问phones/emails列表的地方,先判断isNotEmpty,再安全获取first.value,彻底避免空列表取元素的错误。
  • 格式化复用:把重复的字符串处理逻辑抽成函数,减少冗余,方便后续维护。
  • 默认值处理:给displayName设置默认值,避免Firebase存储null(可根据需求调整)。
  • 用户ID校验:先判断userID是否为空,避免后续Firestore操作报错。
  • 过滤生效:映射数据时使用filteredContacts而非原contacts,确保过滤逻辑真正生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 01:31:27