如何在Android中以编程方式删除联系人

27

我尝试以下代码来删除与指定号码的联系人:

private void removeContact(Context context, String phone) {
    //context.getContentResolver().delete(Contacts.Phones.CONTENT_URI, phone, null);
    context.getContentResolver().delete(Contacts.Phones.CONTENT_URI,
          Contacts.PhonesColumns.NUMBER+"=?", new String[] {phone});
}

但是我得到了这个异常:

java.lang.UnsupportedOperationException: Cannot delete that URL: content://contacts/phones
    at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:130)
    at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:110)
    at android.content.ContentProviderProxy.delete(ContentProviderNative.java:362)
    at android.content.ContentResolver.delete(ContentResolver.java:386)

请问您能告诉我如何解决我的问题吗?

谢谢。

7个回答

24
删除所有联系人,请使用以下代码:
ContentResolver cr = getContentResolver();
    Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,
            null, null, null, null);
    while (cur.moveToNext()) {
        try{
            String lookupKey = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
            Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey);
            System.out.println("The uri is " + uri.toString());
            cr.delete(uri, null, null);
        }
        catch(Exception e)
        {
            System.out.println(e.getStackTrace());
        }
    }

要删除特定联系人,请修改查询

cr.delete(uri, null, null);

希望有所帮助!


1
是的,它正在工作,但问题在于它没有从联系人2.db(Android数据库)数据库的“数据”表中删除联系人。 - Vivek
2
修改查询为什么? - CHarris
java.lang.IllegalStateException: 无法从CursorWindow读取第1323行,第16列。在访问数据之前,请确保正确初始化Cursor。我正在尝试从设备中删除约100k个联系人,每删除1323个联系人后会出现此错误。 - Omkar

21

这就是我们需要的全部内容。 要删除给定电话号码和姓名的联系人。

public static boolean deleteContact(Context ctx, String phone, String name) {
    Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phone));
    Cursor cur = ctx.getContentResolver().query(contactUri, null, null, null, null);
    try {
        if (cur.moveToFirst()) {
            do {
                if (cur.getString(cur.getColumnIndex(PhoneLookup.DISPLAY_NAME)).equalsIgnoreCase(name)) {
                    String lookupKey = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
                    Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey);
                    ctx.getContentResolver().delete(uri, null, null);
                    return true;
                }

            } while (cur.moveToNext());
        }

    } catch (Exception e) {
        System.out.println(e.getStackTrace());
    } finally {
        cur.close();
    }
    return false;
}

记得添加读写联系人权限

<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />

如果联系人没有电话,您将无法使用此功能删除。 - AliSh
有没有办法修改它只根据姓名删除联系人? - TW80000

9

您的清单文件中是否声明了适当的权限?

在 Android 允许您操作联系人提供程序之前,您需要添加 android.permission.READ_CONTACTSandroid.permission.WRITE_CONTACTS uses-permission 标签:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.android.app.myapp" >

  <uses-permission android:name="android.permission.READ_CONTACTS" />
  <uses-permission android:name="android.permission.WRITE_CONTACTS" />

</manifest>

1
权限问题是最让我头疼的。曾经有一次,我试了一个星期才发现我的震动代码一直崩溃,原来需要获取震动权限... - num1

7
一个晚回答,但也许有所帮助:
如果您查看ContactsProvider的源代码并搜索"matcher.addURI"(不要惊讶,如果它在中途停止加载...一两分钟后会恢复加载),那么您会发现它有一组有限的URI方案可以处理。它有一个处理程序用于"phones/#",但没有用于"phones"的处理程序,这是您需要的。
这意味着,没有删除所有电话号码的代码,您必须首先获取所有号码的ID,然后逐个删除每个号码。当然,这需要更多的CPU和内存资源,但至少它可以工作。
以下代码删除特定号码。请注意,我没有测试过这段代码,但它与我用于删除给定人员所有号码的代码90%相同,因为Android无法删除“people /#/phones”,而是“people /#/phones /#” 编辑:我刚意识到我误解了问题。我以为你想删除电话号码,我的代码可以做到。但现在我明白你想删除联系人。
private void deletePhoneNumber(Uri peopleUri, String numberToDelete) {

    Uri.Builder builder = peopleUri.buildUpon();
    builder.appendEncodedPath(People.Phones.CONTENT_DIRECTORY);
    Uri phoneNumbersUri = builder.build();


    String[] mPhoneNumberProjection = { People.Phones._ID, People.Phones.NUMBER };
    Cursor cur = resolver.query(phoneNumbersUri, mPhoneNumberProjection,
            null, null, null);

    ArrayList<String> idsToDelete = new ArrayList<String>();

    if (cur.moveToFirst()) {
        final int colId = cur.getColumnIndex(People.Phones._ID);
        final int colNumber = cur.getColumnIndex(People.Phones.NUMBER);

        do {
            String id = cur.getString(colId);
            String number = cur.getString(colNumber);
            if(number.equals(numberToDelete))
                idsToDelete.add(id);
        } while (cur.moveToNext());
    }
    cur.close();

    for (String id : idsToDelete) {
        builder.encodedPath(People.Phones.CONTENT_DIRECTORY + "/" + id);
        phoneNumbersUri = builder.build();
        resolver.delete(phoneNumbersUri, "1 = 1", null);
    }
}

代码有点冗长,因为它做了两个假设:
  • 可能有多行需要删除(例如,数字存储了两次)
  • 获取光标、删除行并继续使用光标可能不安全
这两个假设都通过首先将idsToDelete存储在一个ArrayList中,然后再进行删除来处理。
您还可以考虑规范化您要搜索的号码,并使用列People.Phones.NUMBER_KEY,因为它包含规范化形式的号码。

也许是我太蠢了,但我花了一段时间才弄清楚调用这个函数需要像deletePhoneNumber(Contacts.CONTENT_URI,"555")这样才能工作。除此之外,这是一个很好的答案,谢谢! - pgsandstrom

1
更好的删除联系人的方式是使用联系人ID删除所有原始联系人。
    final ArrayList ops = new ArrayList();
    final ContentResolver cr = getContentResolver();
    ops.add(ContentProviderOperation
            .newDelete(ContactsContract.RawContacts.CONTENT_URI)
            .withSelection(
                    ContactsContract.RawContacts.CONTACT_ID
                            + " = ?",
                    new String[] { allId.get(i) })
            .build());

        try {
            cr.applyBatch(ContactsContract.AUTHORITY, ops);
            int deletecontact = serialList.get(allId.get(i));

        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        }
        //background_process();
        ops.clear();
    }

不要忘记添加权限。
        <uses-permission android:name="android.permission.READ_CONTACTS"/>
        <uses-permission android:name="android.permission.WRITE_CONTACTS"/>

为什么要将变量声明为final?此外,您不需要cr变量->可以直接使用getContentResolver().applyBatch(*)。 - user8462556

1
这段代码完美地移除了联系人标识符 (ContactsContract.Contacts._ID) 上的联系人。需要独立删除该联系人的所有电话号码注册。
  fun deleteContactById(id: String) {
      val cr = context.contentResolver
      val cur = cr.query(ContactsContract.Contacts.CONTENT_URI,
                    null, null, null, null)
      cur?.let {
          try {
                    if (it.moveToFirst()) {
                        do {
                            if (cur.getString(cur.getColumnIndex(ContactsContract.PhoneLookup._ID)) == id) {
                                val lookupKey = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY))
                                val uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey)
                                cr.delete(uri, null, null)
                                break
                            }

                        } while (it.moveToNext())
                    }

                } catch (e: Exception) {
                    println(e.stackTrace)
                } finally {
                    it.close()
                }
            }
}

0
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,
        null, null, null, null);
while (cur.moveToNext()) {
    try{
        String lookupKey = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
        Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey);
        System.out.println("The uri is " + uri.toString());
        cr.delete(uri, null, null);
    }
    catch(Exception e)
    {
        System.out.println(e.getStackTrace());
    }
}

我使用了这段代码来删除联系人。它可以删除SIM卡上的联系人,也可以删除存储在手机存储器中的联系人。


2
请注意以上代码。以它目前的形式,我相信它会删除你手机上的所有联系人。 - CHarris
这段代码刚刚删除了我手机通讯录里的所有内容!大家要小心啊! - JPerk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接