如何在 Android Studios 中更新联系人的电话号码

Posted

技术标签:

【中文标题】如何在 Android Studios 中更新联系人的电话号码【英文标题】:How can I update the phone numbers of contacts in Android Studios 【发布时间】:2020-12-24 02:48:21 【问题描述】:

我是使用 android studio 开发应用程序的新手,我决定制作一个应用程序来编辑我的电话联系人的电话号码作为我的第一个测试应用程序。

我使用一个类来获取有关我手机上所有联系人的信息,然后我创建了一个列表视图,其中显示了联系人的姓名、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 '%?%'" 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 ");
    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);

如何使上述脚本工作以使用我拥有的信息更新正确的联系人表。

【问题讨论】:

【参考方案1】:

我认为您对 contactId 和 rawContactId 有混淆。

当您从设备读取所有联系人时,您将获得该联系人的 contactId,但您尝试使用的 updateContactPhoneByID 方法期待的是 rawContactId,这是不同的。

简而言之,ContactsContract.Contacts 表中的每个 Contact 由多个 RawContacts 组成,每个通常由不同的应用程序或帐户同步(例如,一个来自您个人 Google 帐户的 RawContact,另一个来自您工作的 RawContact Google 帐户、Whatsapp 的另一个帐户和 Yahoo 的一个帐户),所有这些 RawContacts 的详细信息都加入组成一个联系人资料。

我不确定您希望如何进行编辑,如果一个联系人有多个电话号码,您是想用一个新电话号码替换所有这些电话,还是允许用户输入多个电话你的编辑屏幕?

无论如何,这里有一个小的 kotlin 函数,它接受一个 contactId 和一个现有的电话号码 X,并用一个新号码替换那个单一的号码。 我希望你能适应你的需要。

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)

请注意,existingNumber 参数必须与 ContactsContract DB 中的字符串完全匹配。

【讨论】:

您好,感谢您抽出宝贵时间回答这个问题。我想要做的是用新的电话号码替换每个联系人的所有电话号码(手机、工作电话、家庭电话等)(我用另一个运行良好的功能随机生成这些新号码。)。我要测试你的功能,看看它是否适合我。

以上是关于如何在 Android Studios 中更新联系人的电话号码的主要内容,如果未能解决你的问题,请参考以下文章

Android Studios - 在布局编辑器中调整 VideoView 大小

Android Studios:Android 设备管理器在文件资源管理器中未显示 Nougat 7.0 的文件

在安装liunx下的android studios出现的错误

Android Studios崩溃[重复]

如何在 Android 中编辑现有联系人?

如何检测更新的android联系人并同步到firestore