Android插入日歷提醒
本文用于說(shuō)明Android日歷功能
Android系統(tǒng)提供了插入日功能。第三方應(yīng)用可以自行插入日歷事件冬筒,系統(tǒng)日歷會(huì)根據(jù)日歷事件在設(shè)定的時(shí)間彈出通知提醒用戶(hù)瞪慧。
Android系統(tǒng)日歷提醒原理
Android提供了一個(gè)provider:com.android.providers.calendar? 該provider提供一套接口供開(kāi)發(fā)者使用。
日歷事件存儲(chǔ)
日歷事件存儲(chǔ)在數(shù)據(jù)庫(kù)里部念,數(shù)據(jù)庫(kù)的路徑是:
/data/data/com.android.providers.calendar/databases/calendar.db
日歷事件數(shù)據(jù)格式
日歷事件主要涉及三個(gè)數(shù)據(jù)結(jié)構(gòu)弃酌,也是上面說(shuō)的數(shù)據(jù)庫(kù)里的三個(gè)表:Calendars、Events儡炼、Reminders
Calendars
存儲(chǔ)的是日歷帳號(hào)信息妓湘。每個(gè)app都可以往日歷數(shù)據(jù)庫(kù)里注冊(cè)多個(gè)帳號(hào),也可以使用數(shù)據(jù)庫(kù)里已有的帳號(hào)榜贴。一般來(lái)講,每個(gè)app注冊(cè)一個(gè)帳號(hào)即可妹田。當(dāng)不需要使用這個(gè)日的時(shí)候唬党,刪除這個(gè)日歷。與這個(gè)日歷綁定的事件和提醒都會(huì)被刪除鬼佣。
表結(jié)構(gòu)為:
Events
日歷事件驶拱,比如今天下午三點(diǎn)要去讀書(shū)。這就是一個(gè)事件晶衷。在Events表里蓝纲,每一行數(shù)據(jù)都是一個(gè)事件
表結(jié)構(gòu)為:
表中有一個(gè)字段是calendar_id。用于標(biāo)識(shí)該事件屬于哪個(gè)帳號(hào)晌纫,該值對(duì)應(yīng)著Calendars表中的_id字段
Reminders
日歷提醒税迷,有了日歷事件。并不代表就會(huì)產(chǎn)生提醒锹漱。如果某個(gè)日歷事件需要提醒用戶(hù)箭养。需要對(duì)這個(gè)日歷事件創(chuàng)建一個(gè)提醒,告訴系統(tǒng)凌蔬,該事件需要以什么方式提醒用戶(hù)
表結(jié)構(gòu):
表中event_id用于標(biāo)識(shí)該提醒屬于哪個(gè)日歷事件露懒。該值對(duì)應(yīng)著Events表中的_id字段
以上三個(gè)表的字段含義這里就不一一解釋了。具體可以看https://developer.android.com/reference/android/provider/CalendarContract.Calendars
https://developer.android.com/reference/android/provider/CalendarContract.Events
https://developer.android.com/reference/android/provider/CalendarContract.Reminders
日歷開(kāi)發(fā)API
1. 存儲(chǔ)日歷帳號(hào)
? 存儲(chǔ)帳號(hào)信息的URI:android.provider.CalendarContract.Calendars#CONTENT_URI
? DEMO CODE
//Calendar 為自定義日歷數(shù)據(jù)格式砂心,用于存儲(chǔ)用戶(hù)創(chuàng)建的帳號(hào)信息
fun addCalendar(calendar: Calendar, resolver:
? ContentResolver): Long {
??? val? calendars = queryCalendar(calendar.ACCOUNT_NAME, calendar.ACCOUNT_TYPE,? calendar.OWNER_ACCOUNT, resolver)
??? if? (calendars != null && calendars.size > 0) {
? Log.d("lzqtest", "CalendarWrapper.addCalendar: already? has a same calendar "+calendars)
? return CalendarStatus.ALREADY_EXIST.value()
??? }
??? val? contentValues = ContentValues()
??? if? (!calendar.ACCOUNT_TYPE.isNullOrEmpty())? {
? contentValues.put(Calendars.ACCOUNT_TYPE,? calendar.ACCOUNT_TYPE)
??? }
??? if? (!calendar.ACCOUNT_NAME.isNullOrEmpty())? {
? contentValues.put(Calendars.ACCOUNT_NAME,? calendar.ACCOUNT_NAME)
??? }
??? if? (!calendar.NAME.isNullOrEmpty()) {
? contentValues.put(Calendars.NAME,? calendar.NAME)
??? }
??? if? (calendar.DIRTY != null) {
? contentValues.put(Calendars.DIRTY,? calendar.DIRTY)
??? }
??? if? (!calendar.MUTATORS.isNullOrEmpty())? {
? contentValues.put(Calendars.MUTATORS,? calendar.MUTATORS)
??? }
??? if? (!calendar.CALENDAR_DISPLAY_NAME.isNullOrEmpty())? {
? contentValues.put(Calendars.CALENDAR_DISPLAY_NAME,? calendar.CALENDAR_DISPLAY_NAME)
??? }
??? if? (calendar.CALENDAR_COLOR != null) {
? contentValues.put(Calendars.CALENDAR_COLOR,? calendar.CALENDAR_COLOR)
??? }
??? if? (calendar.CALENDAR_ACCESS_LEVEL != null) {
? contentValues.put(Calendars.CALENDAR_ACCESS_LEVEL,? calendar.CALENDAR_ACCESS_LEVEL)
??? }
??? if? (!calendar.CALENDAR_LOCATION.isNullOrEmpty())? {
? contentValues.put(Calendars.CALENDAR_LOCATION,? calendar.CALENDAR_LOCATION)
??? }
??? if? (!calendar.CALENDAR_TIME_ZONE.isNullOrEmpty())? {
? contentValues.put(Calendars.CALENDAR_TIME_ZONE,? calendar.CALENDAR_TIME_ZONE)
??? }
??? if? (!calendar.OWNER_ACCOUNT.isNullOrEmpty())? {
? contentValues.put(Calendars.OWNER_ACCOUNT,? calendar.OWNER_ACCOUNT)
??? }
??? if? (calendar.MAX_REMINDERS != null) {
? contentValues.put(Calendars.MAX_REMINDERS,? calendar.MAX_REMINDERS)
??? }
??? if? (!calendar.ALLOWED_REMINDERS.isNullOrEmpty())? {
? contentValues.put(Calendars.ALLOWED_REMINDERS,? calendar.ALLOWED_REMINDERS)
??? }
??? if? (!calendar.ALLOWED_AVAILABILITY.isNullOrEmpty())? {
? contentValues.put(Calendars.ALLOWED_AVAILABILITY,? calendar.ALLOWED_AVAILABILITY)
??? }
??? if? (!calendar.ALLOWED_ATTENDEE_TYPES.isNullOrEmpty())? {
? contentValues.put(Calendars.ALLOWED_ATTENDEE_TYPES,? calendar.ALLOWED_ATTENDEE_TYPES)
??? }
??? var uri? = Calendars.CONTENT_URI
??? //uri需要通過(guò)appendQueryParameter 追加參數(shù)懈词,否則會(huì)報(bào)插入失敗的錯(cuò)誤
??? uri= uri.buildUpon()
? .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true")
? .appendQueryParameter(Calendars.ACCOUNT_NAME,? calendar.ACCOUNT_NAME)
? .appendQueryParameter(Calendars.ACCOUNT_TYPE,
? calendar.ACCOUNT_TYPE)
? .build()
//插入日歷帳號(hào)信息
???? val? ret=resolver.insert(uri, contentValues)
??? return? if (ret!=null) ContentUris.parseId(ret) else CalendarStatus.FAIL.value()
}
2. 存儲(chǔ)日歷事件
? 存儲(chǔ)日歷事件URI:android.provider.CalendarContract.Events#CONTENT_URI
? DEMO CODE
// EVENT 為自定義對(duì)象,用于存儲(chǔ)用戶(hù)日歷事件信息
fun addEvent(event: Event, resolver:
? ContentResolver): Long {
??? val? events = queryEventByCalendarId(event.CALENDAR_ID, resolver)
??? if? (events != null && events.size > 0) {
??????? for? (data in events) {
? if (data.TITLE?.equals(event.TITLE) == true
??????????????????? && data.DTSTART? == event.DTSTART
??????????????????? && data.DTEND ==? event.DTEND) {
? Log.d("lzqtest", "EventWrapper.addEvent: alread exist? event $events ")
? return CalendarStatus.ALREADY_EXIST.value()
? }
??????? }
??? }
??? if? (event.CALENDAR_ID == null || event.CALENDAR_ID!! < 0) {
? return CalendarStatus.PARAMETER_ERROR.value()
??? }
??? val? contentValues = ContentValues()
? contentValues.put(CalendarContract.Events.CALENDAR_ID, event.CALENDAR_ID)
??? if? (!event.TITLE.isNullOrEmpty())
? contentValues.put(CalendarContract.Events.TITLE, event.TITLE)
??? if? (!event.EVENT_LOCATION.isNullOrEmpty())
? contentValues.put(CalendarContract.Events.EVENT_LOCATION, event.EVENT_LOCATION)
??? if? (!event.DESCRIPTION.isNullOrEmpty())? {
? contentValues.put(CalendarContract.Events.DESCRIPTION, event.DESCRIPTION)
??? }
??? if? (event.EVENT_COLOR != null) {
? contentValues.put(CalendarContract.Events.EVENT_COLOR, event.EVENT_COLOR)
??? }
??? if? (event.STATUS != null) {
? contentValues.put(CalendarContract.Events.STATUS, event.STATUS)
??? }
??? if? (event.SELF_ATTENDEE_STATUS != null) {
? contentValues.put(CalendarContract.Events.SELF_ATTENDEE_STATUS, event.SELF_ATTENDEE_STATUS)
??? }
??? if? (event.DTSTART != null) {
? contentValues.put(CalendarContract.Events.DTSTART, event.DTSTART)
??? }
??? if? (!event.EVENT_TIMEZONE.isNullOrEmpty())? {
? contentValues.put(CalendarContract.Events.EVENT_TIMEZONE, event.EVENT_TIMEZONE)
??? }
??? if? (event.ALL_DAY != null) {
? contentValues.put(CalendarContract.Events.ALL_DAY, event.ALL_DAY)
??? }
??? if? (event.ACCESS_LEVEL != null) {
? contentValues.put(CalendarContract.Events.ACCESS_LEVEL, event.ACCESS_LEVEL)
??? }
??? if? (event.AVAILABILITY != null) {
? contentValues.put(CalendarContract.Events.AVAILABILITY, event.AVAILABILITY)
??? }
??? if? (event.HAS_ALARM != null) {
? contentValues.put(CalendarContract.Events.HAS_ALARM, event.HAS_ALARM)
??? }
??? if (event.HAS_EXTENDED_PROPERTIES? != null) {
? contentValues.put(CalendarContract.Events.HAS_EXTENDED_PROPERTIES, event.HAS_EXTENDED_PROPERTIES)
??? }
??? if? (!event.RRULE.isNullOrEmpty()) {
? contentValues.put(CalendarContract.Events.RRULE, event.RRULE)
??? }
??? if? (!event.RDATE.isNullOrEmpty()) {
? contentValues.put(CalendarContract.Events.RDATE, event.RDATE)
??? }
??? if? (!event.EXRULE.isNullOrEmpty()) {
? contentValues.put(CalendarContract.Events.EXRULE, event.EXRULE)
??? }
??? if? (!event.EXDATE.isNullOrEmpty()) {
? contentValues.put(CalendarContract.Events.EXDATE, event.EXDATE)
??? }
??? if? (event.ORIGINAL_ID != null) {
? contentValues.put(CalendarContract.Events.ORIGINAL_ID, event.ORIGINAL_ID)
??? }
??? if? (event.LAST_DATE != null) {
? contentValues.put(CalendarContract.Events.LAST_DATE, event.LAST_DATE)
??? }
??? if? (event.HAS_ATTENDEE_DATA != null) {
? contentValues.put(CalendarContract.Events.HAS_ATTENDEE_DATA, event.HAS_ATTENDEE_DATA)
??? }
??? if? (event.GUESTS_CAN_MODIFY != null) {
? contentValues.put(CalendarContract.Events.GUESTS_CAN_MODIFY, event.GUESTS_CAN_MODIFY)
??? }
??? if? (event.GUESTS_CAN_INVITE_OTHERS != null) {
? contentValues.put(CalendarContract.Events.GUESTS_CAN_INVITE_OTHERS, event.GUESTS_CAN_INVITE_OTHERS)
??? }
??? if? (event.GUESTS_CAN_SEE_GUESTS != null) {
? contentValues.put(CalendarContract.Events.GUESTS_CAN_SEE_GUESTS, event.GUESTS_CAN_SEE_GUESTS)
??? }
??? if? (!event.ORGANIZER.isNullOrEmpty())? {
? contentValues.put(CalendarContract.Events.ORGANIZER, event.ORGANIZER)
??? }
??? if? (event.DELETED != null) {
? contentValues.put(CalendarContract.Events.DELETED, event.DELETED)
??? }
??? if? (!event.EVENT_END_TIMEZONE.isNullOrEmpty())? {
? contentValues.put(CalendarContract.Events.EVENT_END_TIMEZONE, event.EVENT_END_TIMEZONE)
??? }
??? if? (event.DTEND != null) {
? contentValues.put(CalendarContract.Events.DTEND, event.DTEND)
??? }
? Log.d("lzqtest", "EventWrapper.addEvent: insert event? now ")
??? val ret? = resolver.insert(CalendarContract.Events.CONTENT_URI,? contentValues)
? Log.d("lzqtest", "EventWrapper.addEvent: insert result? ret=$ret ")
??? return? if (ret != null) ContentUris.parseId(ret) else CalendarStatus.FAIL.value()
}
3. 存儲(chǔ)日歷提醒
? 存儲(chǔ)日歷提醒URI:android.provider.CalendarContract.Reminders#CONTENT_URI
? DEMO CODE
fun addReminder(reminder: Reminder, resolver:
? ContentResolver): Long? {
??? val? reminders = queryMinderByEventId(reminder.EVENT_ID, resolver)
??? if? (reminders != null && reminders.size > 0) {
??????? for? (data in reminders) {
? if (data.MINUTES == (reminder.MINUTES)
? && data.METHOD == reminder.METHOD
? ) {
? Log.d(
??????????????????? "lzqtest",
? "ReminderWrapper.addReminder: alread exist reminder=$reminders? "
? )
? return CalendarStatus.ALREADY_EXIST.value()
? }
??????? }
??? }
??? if? (reminder.EVENT_ID == null) {
? Log.d("lzqtest", "ReminderWrapper.addReminder: EVENT_ID? is null ")
? return CalendarStatus.PARAMETER_ERROR.value()
??? }
??? val? contentValues = ContentValues()
? contentValues.put(CalendarContract.Reminders.EVENT_ID, reminder.EVENT_ID)
??? if? (reminder.METHOD != null) {
? contentValues.put(CalendarContract.Reminders.METHOD, reminder.METHOD)
??? }
??? if? (reminder.MINUTES != null) {
? contentValues.put(CalendarContract.Reminders.MINUTES, reminder.MINUTES)
??? }
? Log.d("lzqtest", "ReminderWrapper.addReminder: add? reminder now ")
??? val ret? = resolver.insert(CalendarContract.Reminders.CONTENT_URI, contentValues)
? Log.d("lzqtest", "ReminderWrapper.addReminder: result? ret=$ret ")
??? return? if (ret == null) CalendarStatus.FAIL.value()? else ContentUris.parseId(ret)
}
按以上方式插入日歷數(shù)據(jù)到provider后辩诞,系統(tǒng)日歷app即可顯示插入的日歷提醒坎弯。第三方日歷app不一定會(huì)顯示。這取決于第三方日歷app會(huì)不會(huì)去讀取系統(tǒng)日歷數(shù)據(jù)庫(kù)
demo code已上傳至https://github.com/lzqnet/CalendarManager