英文:
How can I update the phone numbers of contacts in Android Studios
问题
我是新手,正在使用Android Studio开发应用程序,并决定制作一个应用程序来编辑我的手机联系人的电话号码,作为我的第一个测试应用程序。
我使用一个类来获取有关我手机上所有联系人的信息,然后我创建了一个ListView,显示联系人的姓名、ID、头像和已注册的电话号码。
信息已从ContactsContract.Contacts表中获取。到目前为止,一切都运行良好。
但现在我必须编辑所有联系人的电话号码,但我不知道如何确切地做到这一点。我一直在查阅Android开发者文档,但找不到可以帮助我的东西。在这种情况下,我不想使用Intent。
我有这个用于获取所有联系人信息的Kotlin类:
@file:Suppress("unused")
package com.example.uimx
import android.Manifest
import android.content.ContentUris
import android.content.Context
import android.net.Uri
import android.provider.ContactsContract
import androidx.annotation.RequiresPermission
@RequiresPermission(Manifest.permission.READ_CONTACTS)
fun Context.isContactExists(
phoneNumber: String
): Boolean {
val lookupUri = Uri.withAppendedPath(
ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(phoneNumber)
)
val projection = arrayOf(
ContactsContract.PhoneLookup._ID,
ContactsContract.PhoneLookup.NUMBER,
ContactsContract.PhoneLookup.DISPLAY_NAME
)
contentResolver.query(lookupUri, projection, null, null, null).use {
return (it?.moveToFirst() == true)
}
}
@RequiresPermission(Manifest.permission.READ_CONTACTS)
@JvmOverloads
fun Context.retrieveAllContacts(
searchPattern: String = "",
retrieveAvatar: Boolean = true,
limit: Int = -1,
offset: Int = -1
): List<ContactData> {
val result: MutableList<ContactData> = mutableListOf()
contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
CONTACT_PROJECTION,
if (searchPattern.isNotBlank()) "${ContactsContract.Contacts.DISPLAY_NAME_PRIMARY} LIKE '%$searchPattern%'" else null,
if (searchPattern.isNotBlank()) arrayOf(searchPattern) else null,
if (limit > 0 && offset > -1) "${ContactsContract.Contacts.DISPLAY_NAME_PRIMARY} ASC LIMIT $limit OFFSET $offset"
else ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + " ASC"
)?.use {
if (it.moveToFirst()) {
do {
val contactId = it.getLong(it.getColumnIndex(CONTACT_PROJECTION[0]))
val name = it.getString(it.getColumnIndex(CONTACT_PROJECTION[2])) ?: ""
val hasPhoneNumber = it.getString(it.getColumnIndex(CONTACT_PROJECTION[3])).toInt()
val phoneNumber: List<String> = if (hasPhoneNumber > 0) {
retrievePhoneNumber(contactId)
} else mutableListOf()
val avatar = if (retrieveAvatar) retrieveAvatar(contactId) else null
result.add(ContactData(contactId, name, phoneNumber, avatar))
} while (it.moveToNext())
}
}
return result
}
private fun Context.retrievePhoneNumber(contactId: Long): List<String> {
val result: MutableList<String> = mutableListOf()
contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
"${ContactsContract.CommonDataKinds.Phone.CONTACT_ID} =?",
arrayOf(contactId.toString()),
null
)?.use {
if (it.moveToFirst()) {
do {
result.add(it.getString(it.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)))
} while (it.moveToNext())
}
}
return result
}
private fun Context.retrieveAvatar(contactId: Long): Uri? {
return contentResolver.query(
ContactsContract.Data.CONTENT_URI,
null,
"${ContactsContract.Data.CONTACT_ID} =? AND ${ContactsContract.Data.MIMETYPE} = '${ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE}'",
arrayOf(contactId.toString()),
null
)?.use {
if (it.moveToFirst()) {
val contactUri = ContentUris.withAppendedId(
ContactsContract.Contacts.CONTENT_URI,
contactId
)
Uri.withAppendedPath(
contactUri,
ContactsContract.Contacts.Photo.CONTENT_DIRECTORY
)
} else null
}
}
private val CONTACT_PROJECTION = arrayOf(
ContactsContract.Contacts._ID,
ContactsContract.Contacts.LOOKUP_KEY,
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
ContactsContract.Contacts.HAS_PHONE_NUMBER
)
data class ContactData(
val contactId: Long,
val name: String,
val phoneNumber: List<String>,
val avatar: Uri?
)
我有一个准备好接收点击事件的按钮,并调用一个函数,该函数将包含用于替换所有联系人的电话号码的脚本,我将为每个联系人定义新的电话号码。
我有下面这段代码,是我从互联网上找到的,但无法在我的应用程序中使其工作:
private int updateContactPhoneByID(long rawContactId)
{
int ret = 0;
ContentResolver contentResolver = getContentResolver();
// Update data table phone number use contact raw contact id.
if(rawContactId > -1) {
// Update mobile phone number.
updatePhoneNumber(contentResolver, rawContactId, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE, "66666666666666");
// Update work mobile phone number.
updatePhoneNumber(contentResolver, rawContactId, ContactsContract.CommonDataKinds.Phone.TYPE_WORK_MOBILE, "8888888888888888");
// Update home phone number.
updatePhoneNumber(contentResolver, rawContactId, ContactsContract.CommonDataKinds.Phone.TYPE_HOME, "99999999999999999");
ret = 1;
}else
{
ret = 0;
}
return ret;
}
/* Update phone number with raw contact id and phone type.*/
private void updatePhoneNumber(ContentResolver contentResolver, long rawContactId, int phoneType, String newPhoneNumber)
{
// Create content values object.
ContentValues contentValues = new ContentValues();
// Put new phone number value.
contentValues.put(ContactsContract.CommonDataKinds.Phone.NUMBER, newPhoneNumber);
// Create query condition, query with the raw contact id.
StringBuffer whereClauseBuf = new StringBuffer();
// Specify the update contact id.
whereClauseBuf.append(ContactsContract.Data.RAW_CONTACT_ID);
whereClauseBuf.append("=");
whereClauseBuf.append(rawContactId);
// Specify the row data mimetype to phone mimetype( vnd.android.cursor.item/phone_v2 )
whereClauseBuf.append(" and ");
whereClauseBuf.append(ContactsContract.Data.MIMETYPE);
whereClauseBuf.append(" = '");
String mimetype = ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE;
whereClauseBuf.append(mimetype);
whereClauseBuf.append("'");
// Specify phone type.
whereClauseBuf.append(" and ");
where
<details>
<summary>英文:</summary>
I am new to developing apps with android studio, and I decided to make an app to edit the phone numbers of my phone contacts as my first test app.
I use a class to get information about all the contacts that I have on my cell phone, then I have created a listview where I show the contact's name, ID, avatar and registered phone numbers.
The information has been gotten from the ContactsContract.Contacts table. This all works fine, so far.
But now I have to edit the phone numbers of all the contacts, but I don't know exactly how to do it. I've been going through the Android devs documentation but I can't get anything that can help me. I don't want to use Intent in this case.
I have this kotlin class that I use to get the information of all contacts is this:
@file:Suppress("unused")
package com.example.uimx
import android.Manifest
import android.content.ContentUris
import android.content.Context
import android.net.Uri
import android.provider.ContactsContract
import androidx.annotation.RequiresPermission
@RequiresPermission(Manifest.permission.READ_CONTACTS)
fun Context.isContactExists(
phoneNumber: String
): Boolean {
val lookupUri = Uri.withAppendedPath(
ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(phoneNumber)
)
val projection = arrayOf(
ContactsContract.PhoneLookup._ID,
ContactsContract.PhoneLookup.NUMBER,
ContactsContract.PhoneLookup.DISPLAY_NAME
)
contentResolver.query(lookupUri, projection, null, null, null).use {
return (it?.moveToFirst() == true)
}
}
@RequiresPermission(Manifest.permission.READ_CONTACTS)
@JvmOverloads
fun Context.retrieveAllContacts(
searchPattern: String = "",
retrieveAvatar: Boolean = true,
limit: Int = -1,
offset: Int = -1
): List<ContactData> {
val result: MutableList<ContactData> = mutableListOf()
contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
CONTACT_PROJECTION,
if (searchPattern.isNotBlank()) "${ContactsContract.Contacts.DISPLAY_NAME_PRIMARY} LIKE '%?%'" else null,
if (searchPattern.isNotBlank()) arrayOf(searchPattern) else null,
if (limit > 0 && offset > -1) "${ContactsContract.Contacts.DISPLAY_NAME_PRIMARY} ASC LIMIT $limit OFFSET $offset"
else ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + " ASC"
)?.use {
if (it.moveToFirst()) {
do {
val contactId = it.getLong(it.getColumnIndex(CONTACT_PROJECTION[0]))
val name = it.getString(it.getColumnIndex(CONTACT_PROJECTION[2])) ?: ""
val hasPhoneNumber = it.getString(it.getColumnIndex(CONTACT_PROJECTION[3])).toInt()
val phoneNumber: List<String> = if (hasPhoneNumber > 0) {
retrievePhoneNumber(contactId)
} else mutableListOf()
val avatar = if (retrieveAvatar) retrieveAvatar(contactId) else null
result.add(ContactData(contactId, name, phoneNumber, avatar))
} while (it.moveToNext())
}
}
return result
}
private fun Context.retrievePhoneNumber(contactId: Long): List<String> {
val result: MutableList<String> = mutableListOf()
contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
"${ContactsContract.CommonDataKinds.Phone.CONTACT_ID} =?",
arrayOf(contactId.toString()),
null
)?.use {
if (it.moveToFirst()) {
do {
result.add(it.getString(it.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)))
} while (it.moveToNext())
}
}
return result
}
private fun Context.retrieveAvatar(contactId: Long): Uri? {
return contentResolver.query(
ContactsContract.Data.CONTENT_URI,
null,
"${ContactsContract.Data.CONTACT_ID} =? AND ${ContactsContract.Data.MIMETYPE} = '${ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE}'",
arrayOf(contactId.toString()),
null
)?.use {
if (it.moveToFirst()) {
val contactUri = ContentUris.withAppendedId(
ContactsContract.Contacts.CONTENT_URI,
contactId
)
Uri.withAppendedPath(
contactUri,
ContactsContract.Contacts.Photo.CONTENT_DIRECTORY
)
} else null
}
}
private val CONTACT_PROJECTION = arrayOf(
ContactsContract.Contacts._ID,
ContactsContract.Contacts.LOOKUP_KEY,
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
ContactsContract.Contacts.HAS_PHONE_NUMBER
)
data class ContactData(
val contactId: Long,
val name: String,
val phoneNumber: List<String>,
val avatar: Uri?
)
I have a button prepared that receives the click event and calls a function that would have the script to replace all the phone numbers of all the contacts, for new phone numbers that I will define for each contact.
I have this next code that I got on the internet but I can't get it to work in my app.
private int updateContactPhoneByID(long rawContactId)
{
int ret = 0;
ContentResolver contentResolver = getContentResolver();
// Update data table phone number use contact raw contact id.
if(rawContactId > -1) {
// Update mobile phone number.
updatePhoneNumber(contentResolver, rawContactId, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE, "66666666666666");
// Update work mobile phone number.
updatePhoneNumber(contentResolver, rawContactId, ContactsContract.CommonDataKinds.Phone.TYPE_WORK_MOBILE, "8888888888888888");
// Update home phone number.
updatePhoneNumber(contentResolver, rawContactId, ContactsContract.CommonDataKinds.Phone.TYPE_HOME, "99999999999999999");
ret = 1;
}else
{
ret = 0;
}
return ret;
}
/* Update phone number with raw contact id and phone type.*/
private void updatePhoneNumber(ContentResolver contentResolver, long rawContactId, int phoneType, String newPhoneNumber)
{
// Create content values object.
ContentValues contentValues = new ContentValues();
// Put new phone number value.
contentValues.put(ContactsContract.CommonDataKinds.Phone.NUMBER, newPhoneNumber);
// Create query condition, query with the raw contact id.
StringBuffer whereClauseBuf = new StringBuffer();
// Specify the update contact id.
whereClauseBuf.append(ContactsContract.Data.RAW_CONTACT_ID);
whereClauseBuf.append("=");
whereClauseBuf.append(rawContactId);
// Specify the row data mimetype to phone mimetype( vnd.android.cursor.item/phone_v2 )
whereClauseBuf.append(" and ");
whereClauseBuf.append(ContactsContract.Data.MIMETYPE);
whereClauseBuf.append(" = '");
String mimetype = ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE;
whereClauseBuf.append(mimetype);
whereClauseBuf.append("'");
// Specify phone type.
whereClauseBuf.append(" and ");
whereClauseBuf.append(ContactsContract.CommonDataKinds.Phone.TYPE);
whereClauseBuf.append(" = ");
whereClauseBuf.append(phoneType);
// Update phone info through Data uri.Otherwise it may throw java.lang.UnsupportedOperationException.
Uri dataUri = ContactsContract.Data.CONTENT_URI;
// Get update data count.
int updateCount = contentResolver.update(dataUri, contentValues, whereClauseBuf.toString(), null);
}
How to make the above script work to update the correct contact table with the information I have.
</details>
# 答案1
**得分**: 1
我认为您对`contactId`和`rawContactId`存在一些混淆。
当您从设备中读取所有联系人时,您会获得该联系人的`contactId`,但您尝试使用的`updateContactPhoneByID`方法需要一个不同的`rawContactId`。
简而言之,在`ContactsContract.Contacts`表中的每个`Contact`都由多个`RawContacts`组成,通常由不同的应用程序或帐户同步(例如,一个`RawContact`来自您的个人Google帐户,另一个`RawContact`来自您的工作Google帐户,另一个来自WhatsApp,还有一个来自Yahoo),来自所有这些`RawContacts`的详细信息都会合并成一个单独的联系人配置文件。
我不确定您希望进行的编辑方式,如果一个联系人有多个电话号码,您是希望用一个新的电话号码替换所有这些电话,还是允许用户在编辑屏幕上输入多个电话号码?
无论如何,这里有一个小的Kotlin函数,它接受一个`contactId`和一个现有的电话号码X,然后将该单个号码替换为新号码。希望您可以根据自己的需求进行调整。
```kotlin
private fun updatePhone(contactId: Long, existingNumber: String, newNumber: String) {
val contentValues = ContentValues()
contentValues.put(Phone.NUMBER, newNumber)
val where = Data.CONTACT_ID + "=? AND " + Data.MIMETYPE + "=? AND " + Phone.NUMBER + "=?"
val whereArgs = arrayOf((contactId).toString(), Phone.CONTENT_ITEM_TYPE, existingNumber)
contentResolver.update(Data.CONTENT_URI, contentValues, where, whereArgs)
}
请注意,existingNumber
参数必须与ContactsContract数据库中的字符串完全匹配。
英文:
I think you have a confusion about contactId and rawContactId.
When you read all the contacts from the device, you're getting the contactId
of that contact, but the updateContactPhoneByID
method you're trying to use is expecting a rawContactId
which is different.
In a nutshell, every Contact
in the ContactsContract.Contacts
table is comprised out of multiple RawContacts
each is usually synced by some different app or account (e.g. one RawContact from your personal Google account, another RawContact from your work Google account, another one from Whatsapp, and one from Yahoo), the details from ALL these RawContacts
are join to make up a single contact profile.
I'm not sure how you want the edit to work, if a contact has multiple phone numbers, do you want to replace ALL those phones with a single new phone number, or do you allow the user to type multiple phones in your edit screen?
Anyway, here's a small kotlin function that takes a contactId and an existing phone number X and replaces that single number with a new one.
I hope you can adapt it to your needs.
private fun updatePhone(contactId:Long, existingNumber:String, newNumber:String) {
val contentValues = ContentValues()
contentValues.put(Phone.NUMBER, newNumber)
val where = Data.CONTACT_ID + "=?" + " AND " + Data.MIMETYPE + "=?" + " AND " + Phone.NUMBER + "=?"
val whereArgs = arrayOf<String>((contactId).toString(), Phone.CONTENT_ITEM_TYPE, existingNumber)
contentResolver.update(Data.CONTENT_URI, contentValues, where, whereArgs)
}
Note that the existingNumber
param must match the string in the ContactsContract DB exactly.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论