无法删除 Android 个日历

Cannot delete Android calendar

我一直在尝试使用 Android Calendar Provider 来创建本地(非同步)日历,但我最终得到了 ACCOUNT_TYPE 和 [=14 为空的日历=].我可以在以下位置看到它们:

getContentResolver().query(CalendarContract.Calendars.CONTENT_URI, null, CalendarContract.Calendars.ACCOUNT_TYPE + " IS NULL", null, null);

现在我的 Google 日历应用程序在启动时崩溃了:(

我尝试用这段代码删除这些虚拟日历(在成功请求 WRITE_CALENDAR 权限后):

getContentResolver().delete(CalendarContract.Calendars.CONTENT_URI, CalendarContract.Calendars.ACCOUNT_TYPE + " IS NULL", null);

但它引发了以下错误

java.lang.IllegalArgumentException: the name must not be empty: null at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:165) at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135) at android.content.ContentProviderProxy.delete(ContentProviderNative.java:544) at android.content.ContentResolver.delete(ContentResolver.java:1327)

我认为这是由于他们的帐户 type/name 为空造成的。

你知道我怎样才能摆脱它们吗?

注意:设备的 Android 版本是 6.0.1

这是发生了什么(注意所有链接都指向 5.1.1 CalendarProvider,但可以安全地假设它在 Android 6 中工作相同):

  1. 删除日历将始终通过此行: CalendarProvider2.java, line 3206
  2. 现在,在 this line 中,每个要删除的日历都会调用方法 modifyCalendarSubscription(无论您如何 select 编辑它们)。
  3. modifyCalendarSubscription 中,提供商读取每个日历的 ACCOUNT_NAME 和 ACCOUNT_TYPE 列,并尝试创建一个 Account instance
  4. 由于数据库中的帐户名称和类型是 null,它在检查 null 值时在 Account constructor 中崩溃。这就是您看到的 eException 实际被抛出的地方。

因此,无论您如何删除日历,它总是会在 Account 构造函数处失败,因为数据库中的帐户名称为空。

我还没有检查,但您可以使用更新操作覆盖帐户名称和类型。所以尝试将其设置为不是 null.

的值

如果这不起作用,您要么需要 root 访问权限来手动删除日历,要么转到 Settings -> Apps -> All apps -> Calendar storage 并清除整个日历数据库 (clear data)。

更新

覆盖 ACCOUNT_NAMEACCOUNT_TYPE 列只有在您设法匹配通过此行的条件时才有效:CalendarProvider2.java, line 3989 假设该行和到达那里的条件仍然存在在 Android 6. 如果您不将日历 ID 附加到 Uri 并且您不按其 ID select 日历,它认为它应该可以工作。因此,将 delete 设为 update 并将 ACCOUNT_NAMEACCOUNT_TYPE 重置为非 null 的值应该可以解决问题。

我也遇到了同样的问题。我这样更新日历行:

private void updateNullAccount() {
        String selection = CalendarContract.Calendars.ACCOUNT_NAME + " IS NULL";
        Uri uri = CalendarContract.Calendars.CONTENT_URI;
        uri = SyncAdapter.asSyncAdapter(uri);
        ContentValues values = new ContentValues();
        values.put(CalendarContract.Calendars.ACCOUNT_NAME, "NAME BITCH NAME");
        values.put(CalendarContract.Calendars.ACCOUNT_TYPE, CalendarContract.ACCOUNT_TYPE_LOCAL);
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_CALENDAR) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        int count = getContentResolver().update(uri, values, selection, null);
        count++;
    }

并且在我更新的 ACCOUNT_NAME 删除日历后。

当您创建本地日历时,您必须附加查询参数(如同步适配器、帐户名称和帐户类型)并在 ContentValues 中添加相同的帐户名称和帐户类型参数。