在Android KitKat中,com.android.providers.calendar
是从日历存储数据库中删除已删除的日历事件,还是仅将其标记为已删除?
如果它只是在数据库中标记它们,那么它会向数据库中写入什么来反映删除?
我主要感兴趣的是这与本地(非同步)日历的关系,但欢迎对本地和同步日历做出技术回应。
如果这个问题属于Android SE而不是这里,请迁移它。我决定在这里发布它,因为(1)这里更技术的受众实际上可能能够回答这个问题,(2)Android SE可能会意识到这是一个与编程相关的问题,并将其迁移到StackOverflow
Event有一个DELETED
列和一个DIRTY
列。
根据我的经验,CalendarProvider
对这些专栏没有做任何特殊的事情,工作由您决定。所以,若使用delete查询删除事件,它将从数据库中完全删除。
Google Calendar
等日历应用程序是这样工作的:如果某个事件发生了任何类型的更新或删除,则DIRTY
列将设置为true。如果用户删除了事件,则DELETED
列也设置为true。
因此,当SyncAdapter
开始同步时,它会在DIRTY
列中找到未同步的事件,如果DELETED
列也为true,则它会在同步后从数据库中完全删除该事件。
查看CalendarProvider2.java.的来源
正如您所看到的,只有两种情况下事件实际上是从数据库中删除的:
- 它已被同步适配器删除
- 它有一个空的SYNC_ID,这意味着它还没有被同步
如果事件已由同步适配器同步,并且已由普通应用程序删除,则该事件始终标记为已删除(通过将DELETED
列设置为1
)。这对于通知同步适配器删除是必要的。如果事件被完全删除,同步适配器找不到它,它只会假设事件尚未同步,并从服务器上还原它。
关于本地日历:如果同步适配器不支持本地日历,则会立即删除该事件,因为这些事件总是有一个空的SYNC_ID
字段。
请注意,作为普通应用程序,不应尝试修改DELETED
和DIRTY
列。它们的值由日历提供程序设置,并由同步适配器清除。
更新以跟进您的评论
确实,如果某个重复事件没有SYNC_ID
,则不能修改该事件的单个实例。因此,为了修改重复事件的单个实例,您需要分配一个伪SYNC_ID
。非经常性事件不需要这样做。
如果您将此类事件作为非同步适配器应用程序删除,则该事件可能会永远保留在我们的日历数据库中,只需将已删除标志设置为1即可。
为了解决这个问题,我看到了两个选项:
简单但"粗暴"的方式
简单的方法是假装你是相应帐户的同步适配器。到目前为止,我还没有看到任何检查,所以我认为如果你不是同步适配器,日历提供商不会抱怨。然而,您需要确保只为本地帐户(没有真正的同步适配器)执行此操作,否则您将破坏一切。
干净的方式
对于干净的方式,你需要区分几种情况:
删除SYNC_ID
为空的事件
在这种情况下,你可以像之前一样继续删除它
删除具有非空SYNC_ID
的非定期事件
在这种情况下,您需要首先清除SYNC_ID
字段,然后在第二步中删除事件(不过您可以在单个事务中执行此操作)。AFAIK,如果您将SYNC_ID
更改为非同步适配器应用程序,日历提供商不会抱怨。尽管你应该测试一下。
删除重复事件的异常实例(如"取消"实例)
你有两个选择。
-
只需将事件状态设置为
Events.STATUS_CANCELED
,这将保留实例,但它将"显示"为已删除的实例。这就是在Android中通常删除事件实例的方式。 -
清除
ORIGINAL_SYNC_ID
字段,删除实例并向主事件添加一个EXDATE
。
删除具有非空SYNC_ID
的整个重复事件(包括所有异常)
在这里,您唯一的选择是清除SYNC_ID
字段,然后删除该事件。在这种情况下,您可能还必须删除所有具有相同ORIGINAL_SYNC_ID
的异常(不确定Android是否会自动删除)。如果有多个异常,则必须首先清除ORIGINAL_SYNC_ID
,否则它们可能不会被删除。
注意 :我没有测试任何这些。我的回答完全基于我使用CalendarProvider的经验,并通过查看以下来源得出:http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android-apps/5.1.1_r1/com/android/providers/calendar/CalendarProvider2.java