我正在开发一个应用来存储有关事件(尤其是生日)的信息。一个有趣的功能是导入在Google通讯录中找到的每个生日,并立即显示它。该应用程序使用Room DB将联系人保留在事件对象中(基本上,事件由名称,姓氏(可选)和出生日期以及一些其他可选参数定义)
由于我对通讯录提供程序有些困惑(不是每个制造商都使用Google通讯录提供程序,对吗?),我发现的每个答案都已经很旧了,并且没有使用Kotlin,所以我想知道如何基本完成此功能(位于我的主要活动中,在这里我可以轻松访问viewmodel和其他所有内容)
// Import the contacts from Google Contacts
fun importContacts(): Boolean {
// No permission. For now, just send an explanation toast
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, getString(R.string.missing_permission), Toast.LENGTH_SHORT).show()
return false
}
// Phase 1: get every contact having at least a name and a birthday
val contacts = getContacts()
// Phase 2: convert the extracted data in an Event List, verify duplicates
val events = mutableListOf<Event>()
loop@ for (contact in contacts) {
val splitterName = contact.key.split(",")
var name: String
var surname = ""
var date = LocalDate.of(1970,1,1)
when (splitterName.size) {
// Not considering surname only contacts
1 -> name = splitterName[0].trim()
2 -> {
name = splitterName[1].trim()
surname = splitterName[0].trim()
}
else -> continue@loop
}
try { date = LocalDate.parse(contact.value) }
catch (e: Exception) { continue }
val event = Event(id = 0, name = name, surname = surname, originalDate = date)
// Check if the event is duplicate with a query
if (!homeViewModel.checkExisting(it.key, it.value) == 0) events.add(event)
}
// Phase 3: insert the remaining events in the db
events.forEach {
homeViewModel.insert(it)
}
return true
}
// Get the contacts and save them in a list
private fun getContacts(): Map<String, String> {
val nameBirth = mutableMapOf<String, String>()
val resolver: ContentResolver = contentResolver;
val cursor = resolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null)
if (cursor != null) {
if (cursor.count > 0) {
while (cursor.moveToNext()) {
val name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_ALTERNATIVE))
val birth = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.))
nameBirth[name] = "???"
}
}
}
cursor?.close()
return nameBirth
}
尽管我可以轻松地编写第2阶段和第3阶段,但我对处理第一个阶段的最佳方法感到困惑。您可以假设我已经授予了联系人许可权,而我想要的只是我可以用来创建对象的名称,姓氏和日期的列表。
EDIT:所以我根据自己的进度修改了上面的代码。现在,我可以取名字,在名字和姓氏中拆分名字,验证重复项并将联系人插入我的数据库中。剩下的唯一事情就是检索生日并管理可能未指定年份的事实。如您所见,我正在使用LocalDate对象保存日期。
// Import the contacts from Google Contacts
fun importContacts(): Boolean {
// No permission. For now, just send an explanation toast
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, getString(R.string.missing_permission), Toast.LENGTH_SHORT).show()
return false
}
// Phase 1: get every contact having at least a name and a birthday
val contacts = getContacts()
// Phase 2: convert the extracted data in an Event List, verify duplicates
val events = mutableListOf<Event>()
loop@ for (contact in contacts) {
// Take the name and split it to separate name and surname
val splitterName = contact.value[0].split(",")
var name: String
var surname = ""
var date = LocalDate.of(1970,1,1)
when (splitterName.size) {
// Not considering surname only contacts, but considering name only
1 -> name = splitterName[0].trim()
2 -> {
name = splitterName[1].trim()
surname = splitterName[0].trim()
}
else -> continue@loop
}
try {
// Missing year, put 2020 as a placeholder
var parseDate = contact.value[1]
if (contact.value[1].length < 8) parseDate = contact.value[1].replaceFirst("-", "2020")
date = LocalDate.parse(parseDate)
}
catch (e: Exception) { continue }
val event = Event(id = 0, name = name, surname = surname, originalDate = date)
// The duplicate check is performed at entity level
events.add(event)
}
// Phase 3: insert the remaining events in the db
events.forEach {
homeViewModel.insert(it)
}
return true
}
// Get the contacts and save them in a map
private fun getContacts(): Map<String, List<String>> {
val nameBirth = mutableMapOf<String, List<String>>()
// Retrieve name and id
val resolver: ContentResolver = contentResolver
val cursor = resolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null)
if (cursor != null) {
if (cursor.count > 0) {
while (cursor.moveToNext()) {
val id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID))
val name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_ALTERNATIVE))
// Retrieve the birthday
val bd = contentResolver
val bdc: Cursor? = bd.query(ContactsContract.Data.CONTENT_URI, arrayOf(ContactsContract.CommonDataKinds.Event.DATA),
ContactsContract.Data.CONTACT_ID + " = " + id + " AND " + ContactsContract.Data.MIMETYPE + " = '" +
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE + "' AND " + ContactsContract.CommonDataKinds.Event.TYPE +
" = " + ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY, null, ContactsContract.Data.DISPLAY_NAME
)
if (bdc != null) {
if (bdc.count > 0) {
while (bdc.moveToNext()) {
// Using a list as key will prevent collisions on same name
val birthday: String = bdc.getString(0)
val person = listOf<String>(name, birthday)
nameBirth[id] = person
}
}
bdc.close()
}
}
}
}
cursor?.close()
return nameBirth
}
所以这基本上就是我想要的功能。我敢肯定它可以做得更好,但是我在Kotlin中没有特别的参考。它需要联系人,检查其姓名和生日,并管理缺少年份的情况。另外,我只管理“仅名称”的情况,而不是“仅姓氏”的情况。