Flutter使用sqflite无法将contact_service获取的联系人存入本地数据库
Flutter使用sqflite存储联系人到本地数据库解决方案
现有代码问题梳理
- 字段赋值错误:
phone字段错误赋值为联系人姓名displayName,未读取真实手机号数据 - 异步调用遗漏
await:insert方法为异步Future类型,循环调用时未添加等待逻辑,会导致数据库写入操作未完成就提前结束,出现数据丢失 - 联系人手机号结构未处理:
contact_service返回的联系人手机号是List<Item>类型,需手动提取对应值,同时要做空值判断避免空指针异常 - 建表语句不规范:
synced为INTEGER类型,默认值错误添加了单引号,不符合SQL语法规范 - 边界判断缺失:循环固定取前10条联系人,当设备联系人总数小于10时会触发数组越界崩溃
修正后完整代码
import 'dart:io'; import 'package:contacts_service/contacts_service.dart'; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; import 'package:sqflite/sqflite.dart'; class ContactDatabase { static final _databaseName = "contact.db"; static final _databaseVersion = 1; List<Contact> contact = []; ContactDatabase._init(); static Database? _database; static final ContactDatabase instance = ContactDatabase._init(); Future<Database> get database async { if (_database != null) return _database!; _database = await _initDB(); return _database!; } _initDB() async { Directory documentsDirectory = await getApplicationDocumentsDirectory(); String path = join(documentsDirectory.path, _databaseName); return await openDatabase(path, version: _databaseVersion, onCreate: _onCreate); } static final contact_table = 'contacts'; static final id = 'id'; static final name = 'name'; static final phone = 'phone'; static final avatar = 'avatar'; static final synced = 'synced'; // 修正建表语句synced字段默认值格式 static final CREATE_TABLE = "CREATE TABLE $contact_table" "($name TEXT ," "$phone TEXT ," "$avatar TEXT ," "$synced INTEGER DEFAULT 0 ," "$id INTEGER PRIMARY KEY AUTOINCREMENT)"; Future _onCreate(Database db, int version) async { await db.execute(CREATE_TABLE); } Future<int> insert(String table, Map<String, dynamic> row) async { Database db = await instance.database; return await db.insert(table, row, conflictAlgorithm: ConflictAlgorithm.replace); } Future<void> insertContact() async { contact = (await ContactsService.getContacts(withThumbnails: false)).toList(); // 修正边界判断,取实际联系人总数和10的最小值 int loopCount = contact.length < 10 ? contact.length : 10; for (var i = 0; i < loopCount; i++) { // 提取手机号,做空判断处理 String phoneNum = "NA"; if(contact[i].phones != null && contact[i].phones!.isNotEmpty) { phoneNum = contact[i].phones!.first.value ?? "NA"; } Map<String, dynamic> row = { name: contact[i].displayName ?? "未知联系人", phone: phoneNum, avatar: contact[i].avatar != null && contact[i].avatar!.isNotEmpty ? contact[i].avatar.toString() : "NA", synced: 1, }; // 添加await等待写入完成 await insert(contact_table, row); } } Future<List<Map<String, dynamic>>> queryAllRows() async { Database db = await instance.database; return await db.query(contact_table); } }
使用注意事项
- 调用存储方法前需要先申请联系人读取权限,安卓端需在
AndroidManifest.xml中添加READ_CONTACTS权限配置,iOS端需在Info.plist中添加NSContactsUsageDescription权限使用说明 - 调用存储方法时需添加
await等待操作完成:await ContactDatabase.instance.insertContact(); - 如果需要存储同一联系人的多个手机号,可以将手机号列表转为JSON字符串存储,也可以单独建立手机号关联表存储多号码数据
内容的提问来源于stack exchange,提问作者Nitesh Sharma
相关产品推荐
相关产品推荐

