【发布时间】:2021-05-17 07:11:08
【问题描述】:
我正在尝试导入设备联系人并使用复选框列出它们,然后用户选择并将它们发送到其他屏幕并对其执行操作。 我使用了contacts_service 插件并在初始化时使用了以下代码
var selectedContacts = List<Contact>();
List<Contact> _contacts;
Future<void> refreshContacts() async {
var contacts = (await ContactsService.getContacts(
withThumbnails: false, iOSLocalizedLabels: true))
.toList();
setState(() {
_contacts = contacts;
});
}
和列表视图:
_contacts != null
? ListView.builder(
itemCount: _contacts?.length ?? 0,
itemBuilder: (BuildContext context, int index) {
Contact c = _contacts?.elementAt(index);
return CheckboxListTile(
value: selectedContacts.contains(c),
onChanged: (bool value) {
setState(() {
value
? selectedContacts.add(c)//
: selectedContacts.remove(c);//
});
},
title: Text(c.displayName ?? ""),
secondary: CircleAvatar(child: Text(c.initials())),
);
},
)
: Center(
child: CircularProgressIndicator(),
),
我的问题是当应用程序关闭并重新打开复选框消失并且 selectedContacts 为空时。我花了很多时间试图让数据库工作,但我无法让它工作,主要是因为'Contact'类的电话变量是可迭代的,我无法将它保存到数据库中。
我自己创建了具有 id、name、phone 的类,因此将它们分配给数据库会容易得多。
但后来我无法解决 value: selectedContacts.contains(c), 问题,并且复选框也不起作用。我尝试创建自己的包含函数,在其中获取联系人 c 及其电话值并将其与我的列表进行比较,然后查找电话是否匹配并发送 true 和 false 仍然不起作用。
我的想法是 var selectedContacts = 在这里我可以做到 database empty ? List<Contact> : import Contacts from database 之后我想我仍然不知道如何将 selectedContacts 发送到另一个文件和另一个主页但我可以找到它我假设。
我没有尝试过 sharedpref,因为根据我的阅读,它可以存储小尺寸,如果我的用户从 'Contact' 类中选择许多对象,这将是一个问题。
如果我的解释不好,我很抱歉。这不是那么重要,我只是想学习,提前谢谢
更新:我再次尝试使用数据库,我的代码如下所示。 数据库.dart
import 'dart:io' as io;
import 'package:contacts_service/contacts_service.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
class DatabaseHelper{
static final DatabaseHelper _instance = new DatabaseHelper.internal();
factory DatabaseHelper() => _instance;
static Database _db;
DatabaseHelper.internal();
static initDb() async{
io.Directory documentDirectory = await getApplicationDocumentsDirectory();
String path = join(documentDirectory.path,"contactDatabase.db");
var taskDb= await openDatabase(path,version: 1,onCreate: _onCreate);
return taskDb;
}
static void _onCreate(Database db,int version) async{
await db.execute(
"CREATE TABLE contacts(identifier TEXT PRIMARY KEY, displayName TEXT, givenName TEXT, middleName TEXT, familyName TEXT, prefix TEXT, suffix TEXT, company TEXT, jobTitle TEXT, androidAccountType TEXT, androidAccountName TEXT, emails TEXT, phones TEXT, postalAddresses TEXT, avatar TEXT, birthday TEXT, )"
);
}
static Future<void> addContact(Contact c) async{
final Database db = initDb();
await db.insert('contacts', c.toMap(),conflictAlgorithm: ConflictAlgorithm.replace,);
}
static Future<void> deleteContact(Contact c) async{
final Database db = initDb();
await db.delete('contacts', where: "id = ?", whereArgs: [c.identifier],);
}
static Future<List<Contact>> importContacts() async{
final Database db = initDb();
final List<Map<String, dynamic>> maps = await db.query('contacts');
return List.generate(maps.length, (index) => Contact.fromMap(maps[index]));
}
static Future<bool> dbEmpty() async{
final Database db = initDb();
int count = Sqflite.firstIntValue(await db.rawQuery('SELECT COUNT(*) FROM contacts'));
if (count>0){
return true;
}
else
return false;
}
}
我的联系人屏幕看起来像这样。
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:contacts_service/contacts_service.dart';
import 'database.dart';
class ContactScreen extends StatefulWidget {
@override
_ContactScreenState createState() => _ContactScreenState();
}
class _ContactScreenState extends State<ContactScreen> {
void checkDb() async{
List<Contact> selectedContacts = await DatabaseHelper.dbEmpty()?DatabaseHelper.importContacts():List<Contact>();
}
List<Contact> selectedContacts;
List<Contact> _contacts;
DatabaseHelper databaseHelper = new DatabaseHelper();
@override
void initState() {
super.initState();
refreshContacts();
checkDb();
}
Future<void> refreshContacts() async {
// Load without thumbnails initially.
var contacts = (await ContactsService.getContacts(
withThumbnails: false, iOSLocalizedLabels: true))
.toList();
setState(() {
_contacts = contacts;
});
}
void addDb(Contact c){
selectedContacts.add(c);
DatabaseHelper.addContact(c);
}
void deleteDb(Contact c){
selectedContacts.remove(c);
DatabaseHelper.deleteContact(c);
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: _contacts != null
? ListView.builder(
itemCount: _contacts?.length ?? 0,
itemBuilder: (BuildContext context, int index) {
Contact c = _contacts?.elementAt(index);
return CheckboxListTile(
value: selectedContacts.contains(c),
onChanged: (bool value) {
setState(() {
value
? addDb(c)//selectedContacts.add(c)
: deleteDb(c);//selectedContacts.remove(c);
});
},
title: Text(c.displayName ?? ""),
secondary: CircleAvatar(child: Text(c.initials())),
);
},
)
: Center(
child: CircularProgressIndicator(),
),
);
}
}
我无法让这段代码工作。 可以用所有文本创建我的数据库吗?据我了解,contact_service 得到它的 fromMap 就像它的文本一样,所以我也同意了。
contact_service 代码也如下所示:
String identifier, displayName, givenName, middleName, prefix, suffix, familyName, company, jobTitle;
String androidAccountTypeRaw, androidAccountName;
AndroidAccountType androidAccountType;
Iterable<Item> emails = [];
Iterable<Item> phones = [];
Iterable<PostalAddress> postalAddresses = [];
Uint8List avatar;
DateTime birthday;
String initials() {
return ((this.givenName?.isNotEmpty == true ? this.givenName[0] : "") +
(this.familyName?.isNotEmpty == true ? this.familyName[0] : ""))
.toUpperCase();
}
Contact.fromMap(Map m) {
identifier = m["identifier"];
displayName = m["displayName"];
givenName = m["givenName"];
middleName = m["middleName"];
familyName = m["familyName"];
prefix = m["prefix"];
suffix = m["suffix"];
company = m["company"];
jobTitle = m["jobTitle"];
androidAccountTypeRaw = m["androidAccountType"];
androidAccountType = accountTypeFromString(androidAccountTypeRaw);
androidAccountName = m["androidAccountName"];
emails = (m["emails"] as Iterable)?.map((m) => Item.fromMap(m));
phones = (m["phones"] as Iterable)?.map((m) => Item.fromMap(m));
postalAddresses = (m["postalAddresses"] as Iterable)
?.map((m) => PostalAddress.fromMap(m));
avatar = m["avatar"];
try {
birthday = DateTime.parse(m["birthday"]);
} catch (e) {
birthday = null;
}
}
static Map _toMap(Contact contact) {
var emails = [];
for (Item email in contact.emails ?? []) {
emails.add(Item._toMap(email));
}
var phones = [];
for (Item phone in contact.phones ?? []) {
phones.add(Item._toMap(phone));
}
var postalAddresses = [];
for (PostalAddress address in contact.postalAddresses ?? []) {
postalAddresses.add(PostalAddress._toMap(address));
}
final birthday = contact.birthday == null
? null
: "${contact.birthday.year.toString()}-${contact.birthday.month.toString().padLeft(2, '0')}-${contact.birthday.day.toString().padLeft(2, '0')}";
return {
"identifier": contact.identifier,
"displayName": contact.displayName,
"givenName": contact.givenName,
"middleName": contact.middleName,
"familyName": contact.familyName,
"prefix": contact.prefix,
"suffix": contact.suffix,
"company": contact.company,
"jobTitle": contact.jobTitle,
"androidAccountType": contact.androidAccountTypeRaw,
"androidAccountName": contact.androidAccountName,
"emails": emails,
"phones": phones,
"postalAddresses": postalAddresses,
"avatar": contact.avatar,
"birthday": birthday
};
}
Map toMap() {
return Contact._toMap(this);
}
【问题讨论】:
-
请从您的数据库类中添加代码。
-
@fartem 我尝试了很多次并多次删除了代码。现在我的代码与this 非常相似。如果我可以简单地将 Contact 类对象放入数据库,那就太好了,但我认为我不能做可迭代的对象,例如来自常规电话联系人的电子邮件和电话。
-
您可以从数据库中检索数据并对其进行迭代。
-
@fartem 我又试了一次,但没能成功。我没有迭代它,而是使用了contact_service库中的函数,这些函数也做同样的事情(从数据库中获取)。更新帖子
标签: flutter dart flutter-dependencies dart-pub