Android,Contacts Contract:存储和检索自定义数据
Posted
技术标签:
【中文标题】Android,Contacts Contract:存储和检索自定义数据【英文标题】:Android, Contacts Contract: store and retrieve custom data 【发布时间】:2021-12-19 21:43:49 【问题描述】:为了了解 androids ContacsContract 的工作原理,我尝试向联系人添加自定义条目。之后阅读文档、教程和观看 youtube 视频一整天,我仍然没有进一步完成这项任务。
我得到的最接近的是这个文件https://developer.android.com/reference/kotlin/android/provider/ContactsContract.Data 说明
例如,如果您将“最喜欢的歌曲”的数据行添加到 Google 帐户拥有的原始联系人,它不会同步到服务器,因为 Google 同步适配器不会知道如何处理这种数据类型。因此,新数据类型通常与新帐户类型(即新同步适配器)一起引入。
他们写了我正在尝试的内容,但遗憾的是没有提供如何完成此任务的解决方案。如果有人能提供一个简单的示例,将喜欢的歌曲的数据行添加到联系人并通过代码检索它,那就太好了。
__
我自己得到的:
一种获取基本联系信息的方法:
import android.content.ContentResolver
import android.database.Cursor
import android.provider.ContactsContract
fun fetchContacts(resolver: ContentResolver) : MutableList<ItemContact>
var cols = listOf<String>(
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
ContactsContract.CommonDataKinds.Phone._ID,
).toTypedArray()
var cursor : Cursor? = resolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
cols, null, null,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME
)
var contactsList : MutableList<ItemContact>
= emptyList<ItemContact>().toMutableList()
if (cursor != null && cursor.count > 0)
while(cursor.moveToNext())
contactsList.add(ItemContact(
name = cursor.getString(0),
number = cursor.getString(1),
contact_id = cursor.getString(2),
))
return contactsList
及其对应的数据类
data class ItemContact (
val name: String,
val number: String,
val contact_id: String,
)
根据我目前的理解,我需要向给定的联系人添加一个新的 RawContact,代表我的应用程序,并将最喜欢的歌曲添加为单个数据条目,同时创建它。此 RawContact 应该能够使用检索到的contact_id 连接到联系人。然后我需要检查是否存在代表我的应用程序的 RawContact 用于联系人,如果存在,我将能够检索存储的歌曲,否则我在 UI 中留下占位符文本,仍然需要选择歌曲。不知何故,这涉及到一个自定义 Mimetype,但我仍然不确定这是什么以及如何创建一个。
【问题讨论】:
【参考方案1】:首先,让我们回顾一下 ContactsContract DB 的组织方式:
-
联系人表 - 每个联系人包含一行,但几乎没有任何信息
RawContacts 表 - 可以有多行,每行分配给一个联系人 ID(来自上一个表),包含多个数据行的逻辑组,通常用于单个 SyncProvider,例如 Google。
数据表 - 包含 RawContact 的实际数据,每行都有一个 MIMETYPE 列,说明该行的数据类型(电话、电子邮件、姓名等)+ 15 个数据列来保存信息本身。
还有一些伪表,例如您在代码中查询的ContactsContract.CommonDataKinds.Phone
,它基本上查询数据表,但具有特定的 MIMETYPE 值,例如Phone.CONTENT_ITEM_TYPE
。
如果您想实现自己的 SyncProvider,您通常会创建自己的 RawContact 行,将其添加到现有的 Contact_ID 并使用新的 RAW_CONTACT_ID 添加数据行。
然后设备上的 People/Contacts 应用程序,当他们想要呈现有关某个联系人的数据时,将获取它(包括您的)所有 RawContacts 的列表,然后获取所有这些 RawContacts 的所有数据。
如果您只想向现有联系人添加一小段自定义数据,例如向联系人添加“最喜欢的歌曲”,则无需为此创建新的 RawContact,而是可以创建新的数据行并使用自定义 MIMETYPE 将其附加到现有 RawContact,但请记住,您的项目不会同步到 Google 的服务器,但仍可以在本地设备上使用。
我假设您正在关注第二个选项,所以这里有一个示例代码(未经测试):
// you need to get a RawContact ID of the contact you want to add info to
fun addFavoriteSong(context: Context, rawContactId: Long)
val resolver = context.contentResolver
val ops = ArrayList<ContentProviderOperation>()
ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI, true)
.withValue(Data.RAW_CONTACT_ID, rawContactId)
.withValue(Data.MIMETYPE, "vnd.android.cursor.item/vnd.com.example.favorite_song")
.withValue(Data.DATA1, "Paranoid Android")
.withValue(Data.DATA2, "Radiohead")
.withValue(Data.DATA3, "OK Computer")
.build())
try
val results = resolver.applyBatch(ContactsContract.AUTHORITY, ops)
if (results.isEmpty())
return
catch (e: Exception)
e.printStackTrace()
Log.i("Songs Added", "success!");
然后查询该信息以及姓名和电话等其他信息:
fun fetchContacts(resolver: ContentResolver) : MutableCollection<ItemContact>
var cols = arrayOf(
Data.CONTACT_ID,
Data.MIMETYPE,
Data.DISPLAY_NAME,
Phone.NUMBER,
Data.DATA1,
Data.DATA2,
Data.DATA3,
)
// get only rows of MIMETYPE phone and your new custom MIMETYPE
var selection = Data.MIMETYPE + " IN (" + Phone.CONTENT_ITEM_TYPE + ", " + "vnd.android.cursor.item/vnd.com.example.favorite_song" + ")"
var cursor : Cursor? = resolver.query(Data.CONTENT_URI, cols, null, null, Data.CONTACT_ID)
val map = hashMapOf<Long, ItemContact>()
while(cursor != null && cursor.moveToNext())
val contactId = cursor.getLong(0)
val mimetype = cursor.getString(1)
// gets the existing ItemContact from the map or if not found, puts an empty one in the map
val contact = map.getOrPut(contactId) ItemContact()
with(contact)
if (mimetype == Phone.CONTENT_ITEM_TYPE)
contact_id = contactId
name = cursor.getString(2)
number = cursor.getString(3)
else
contact_id = contactId
song = cursor.getString(4)
band = cursor.getString(5)
album = cursor.getString(6)
return map.values
【讨论】:
谢谢,Mimetype 是否有任何限制/约定,或者我可以使用我喜欢的任何字符串,只要它是唯一的?以上是关于Android,Contacts Contract:存储和检索自定义数据的主要内容,如果未能解决你的问题,请参考以下文章
Android 5.1 Contacts源码分析:Contacts模块主要窗口
Android 5.1 Contacts源码分析:Contacts模块ListView Adapter结构
Android 5.1 Contacts源码分析:Contacts模块Fargment结构