Android插入日歷提醒

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市抠忘,隨后出現(xiàn)的幾起案子撩炊,更是在濱河造成了極大的恐慌,老刑警劉巖崎脉,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拧咳,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡囚灼,警方通過(guò)查閱死者的電腦和手機(jī)骆膝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)灶体,“玉大人阅签,你說(shuō)我怎么就攤上這事⌒椋” “怎么了政钟?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)樟结。 經(jīng)常有香客問(wèn)我养交,道長(zhǎng),這世上最難降的妖魔是什么狭吼? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任层坠,我火速辦了婚禮,結(jié)果婚禮上刁笙,老公的妹妹穿的比我還像新娘破花。我一直安慰自己,他們只是感情好疲吸,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布座每。 她就那樣靜靜地躺著,像睡著了一般摘悴。 火紅的嫁衣襯著肌膚如雪峭梳。 梳的紋絲不亂的頭發(fā)上蹂喻,一...
    開(kāi)封第一講書(shū)人閱讀 52,262評(píng)論 1 308
  • 那天葱椭,我揣著相機(jī)與錄音,去河邊找鬼口四。 笑死孵运,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蔓彩。 我是一名探鬼主播治笨,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼驳概,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了旷赖?” 一聲冷哼從身側(cè)響起顺又,我...
    開(kāi)封第一講書(shū)人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎等孵,沒(méi)想到半個(gè)月后稚照,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锐锣,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姿骏。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖分瘦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嘲玫,我是刑警寧澤悦施,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布去团,位于F島的核電站,受9級(jí)特大地震影響土陪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鬼雀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望源哩。 院中可真熱鬧鞋吉,春花似錦励烦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至改抡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間阿纤,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工欠拾, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人藐窄。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像荆忍,于是被迫代替她去往敵國(guó)和親格带。 傳聞我的和親對(duì)象是個(gè)殘疾皇子刹枉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容