Android Calendar 系統日曆提醒、日程同步系統

来源:https://www.cnblogs.com/LiuZhen/archive/2022/07/05/16445297.html
-Advertisement-
Play Games

安卓往系統中添加日程提醒,吭比較多。 首先有個需求(仿製 ios 日曆),為什麼仿製ios呢?這個得問產品了,我只是一個搬磚的程式員 (*´艸`) 捂嘴 大致有日期,時間,重覆設置,自定義重覆設置,位置提醒設置 跟系統日曆的設置類似,畢竟需要同步到系統,所以設置上面保持規範,都是設置好日期時間,然後 ...


安卓往系統中添加日程提醒,吭比較多。

首先有個需求(仿製 ios 日曆),為什麼仿製ios呢?這個得問產品了,我只是一個搬磚的程式員 (*´艸`) 捂嘴

大致有日期,時間,重覆設置,自定義重覆設置,位置提醒設置

跟系統日曆的設置類似,畢竟需要同步到系統,所以設置上面保持規範,都是設置好日期時間,然後重覆項。

一般的日曆添加也比較簡單(重覆規則比較煩),先看效果圖

添加日曆首先得有一個賬戶,這個自己定義一個就行了

/**
     * 添加日曆賬戶,賬戶創建成功則返回賬戶id,否則返回-1
     */
    private fun addCalendarAccount(context: Context): Long {
        val timeZone: TimeZone = TimeZone.getDefault()
        val value = ContentValues()
        value.put(CalendarContract.Calendars.NAME, CALENDARS_NAME)
        value.put(CalendarContract.Calendars.ACCOUNT_NAME, CALENDARS_ACCOUNT_NAME)
        value.put(CalendarContract.Calendars.ACCOUNT_TYPE, CALENDARS_ACCOUNT_TYPE)
        value.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, CALENDARS_DISPLAY_NAME)
        value.put(CalendarContract.Calendars.VISIBLE, 1)//設置日曆可見
        value.put(CalendarContract.Calendars.CALENDAR_COLOR, Color.BLUE)
        //使用的許可權等級
        value.put(
            CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL,
            CalendarContract.Calendars.CAL_ACCESS_OWNER
        )
        value.put(CalendarContract.Calendars.SYNC_EVENTS, 1)//同步到系統
        value.put(CalendarContract.Calendars.CALENDAR_TIME_ZONE, timeZone.getID())
        value.put(CalendarContract.Calendars.OWNER_ACCOUNT, CALENDARS_ACCOUNT_NAME)
        value.put(CalendarContract.Calendars.CAN_ORGANIZER_RESPOND, 0)
        var calendarUri = Uri.parse(CALENDER_URL)
        calendarUri = calendarUri.buildUpon()
            .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true")
            .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_NAME, CALENDARS_ACCOUNT_NAME)
            .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_TYPE, CALENDARS_ACCOUNT_TYPE)
            .build()
        val result = context.contentResolver.insert(calendarUri, value)
        log("addCalendarAccount result $result")
        return if (result == null) -1 else ContentUris.parseId(result)
    }

後面開始常規的日曆添加操作,在UI上選擇好時間,調用系統方法,同步到系統日曆

/**
     * 添加日曆事件
     */
    private fun addCalendarEvent(
        context: Context?,
        reminderTitle: String?,
        description: String?,
        reminderTime: Long,
        rule: String? = null,
    ): Boolean {
        log("addCalendarEvent $rule")
        if (context == null) {
            return false
        }
        val calId = checkAndAddCalendarAccount(context) //獲取日曆賬戶的id
        log("addCalendarEvent calId $calId")
        if (calId < 0) { //獲取賬戶id失敗直接返回,添加日曆事件失敗
            return false
        }
        deleteCalendarEvent(context, reminderTitle, description)
        //添加日曆事件
        val mCalendar = Calendar.getInstance()
        mCalendar.timeInMillis = reminderTime //設置開始時間
        val start = mCalendar.time.time
        val event = ContentValues()
        event.put(CalendarContract.Events.TITLE, reminderTitle)
        event.put(CalendarContract.Events.DESCRIPTION, description)
        event.put(CalendarContract.Events.CALENDAR_ID, calId) //插入賬戶的id
        event.put(CalendarContract.Events.DTSTART, start)//開始時間
        //結束時間 ,如果事件是每天/周,那麼就沒有結束時間
        event.put(CalendarContract.Events.DTEND, start)
        event.put(CalendarContract.Events.HAS_ALARM, 1) //設置有鬧鐘提醒
        event.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().id) //時區
        if (rule != null) {
            event.put(CalendarContract.Events.RRULE, rule)
        }
        val calendarEvent = context.contentResolver.insert(Uri.parse(CALENDER_EVENT_URL), event)
            ?: return false
        log("addCalendarEvent newEvent $calendarEvent")
        //事件提醒的設定
        val reminders = ContentValues()
        reminders.put(CalendarContract.Reminders.EVENT_ID, ContentUris.parseId(calendarEvent))
        reminders.put(CalendarContract.Reminders.MINUTES, 0) // 提前幾分鐘提醒

        reminders.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT)//提醒次數
        val remindUri = context.contentResolver.insert(Uri.parse(CALENDER_REMINDER_URL), reminders)
        log("addCalendarEvent uri $remindUri")
        return remindUri != null
    }

很多設置其實都是固定值,或者系統規定配置,只需要傳入一個日期時間

這樣基本的添加其實已經完成,但是如果需要重覆,自定義等操作,就複雜許多

重覆提醒

首先重覆提醒,也就是上圖中的常規選擇,也就是每小時,每天,每周每年等

在事件中添加重覆規則

val rule = StringBuilder()
        when (repeatType) {
            //永不
            RemindRepeatType.NEVER.value -> {
                return null
            }
            //每小時
            RemindRepeatType.EVERY_HOUR.value -> {
                rule.append("FREQ=HOURLY;INTERVAL=1")
            }
            //每天
            RemindRepeatType.EVERY_DAY.value -> {
                rule.append("FREQ=DAILY;INTERVAL=1")
            }
            //工作日
            RemindRepeatType.EVERY_WORK_DAY.value -> {
                rule.append("FREQ=WEEKLY;INTERVAL=1")
                for (i in 0 until 5) {
                    if (i <= byDayArray.size) {
                        if (i == 0) {
                            rule.append(";BYDAY=${byDayArray[i]}")
                        } else {
                            rule.append(",${byDayArray[i]}")
                        }
                    }
                }
            }
            //周末
            RemindRepeatType.EVERY_WEEKEND.value -> {
                rule.append("FREQ=WEEKLY;INTERVAL=1;BYDAY=${byDayArray[5]},${byDayArray[6]}")
            }
            //每周
            RemindRepeatType.EVERY_WEEK.value -> {
                rule.append("FREQ=WEEKLY;INTERVAL=1")
            }
            //每兩周
            RemindRepeatType.EVERY_TWO_WEEKS.value -> {
                rule.append("FREQ=WEEKLY;INTERVAL=2")
            }
            //每月
            RemindRepeatType.EVERY_MONTH.value -> {
                rule.append("FREQ=MONTHLY;INTERVAL=1")
            }
            //每3個月
            RemindRepeatType.EVERY_THREE_MONTHS.value -> {
                rule.append("FREQ=MONTHLY;INTERVAL=3")
            }
            //每6個月
            RemindRepeatType.EVERY_SIX_MONTHS.value -> {
                rule.append("FREQ=MONTHLY;INTERVAL=6")
            }
            //每年
            RemindRepeatType.EVERY_YEAR.value -> {
                rule.append("FREQ=YEARLY;INTERVAL=1")
            }
      
        }

規則都是通過字元自定義拼接,可讀性比較差

 

FREQ :表示重覆規則的類型, 必須定義

HOURLY:小時、DAILY:天、WEEKLY:周、MONTHLY:月、YEARLY:年

INTERVAL :重覆間隔數

必須為正整數,預設值為1,表示每小時、每天

BYDAY : MO(周一),TU(周二),WE(周三),TU(周四),FR(周五),SA(周六),SU(周日)

比如每個周末重覆:

FREQ=WEEKLY;INTERVAL=1;BYDAY=SA,SU

最後需要添加 ;WKST=SU ,表示從周幾開始,硬性規定。

這隻是常規的重覆項,如果需要自定義重覆項,也差距不大。

//1:日 2:周 3:月 4:年
                when (customRepeatFreq) {
                    1 -> rule.append("FREQ=DAILY;INTERVAL=$customRepeatInterval")
                    2 -> {
                        rule.append("FREQ=WEEKLY;INTERVAL=$customRepeatInterval")
                        customRepeatItems?.let {
                            for (i in it.indices) {
                                val index = it[i] - 1
                                if (index <= byDayArray.size) {
                                    if (i == 0) {
                                        rule.append(";BYDAY=${byDayArray[index]}")
                                    } else {
                                        rule.append(",${byDayArray[index]}")
                                    }
                                }
                            }
                        }
                    }
                    3 -> {
                        rule.append("FREQ=MONTHLY;INTERVAL=$customRepeatInterval")
                        customRepeatItems?.let {
                            for (i in it.indices) {
                                val index = it[i] - 1
                                if (index <= byMonthDayArray.size) {
                                    if (i == 0) {
                                        rule.append(";BYMONTHDAY=${byMonthDayArray[index]}")
                                    } else {
                                        rule.append(",${byMonthDayArray[index]}")
                                    }
                                }
                            }
                        }
                    }
                    4 -> {
                        rule.append("FREQ=YEARLY;INTERVAL=$customRepeatInterval")
                        customRepeatItems?.let {
                            for (i in it.indices) {
                                val index = it[i] - 1
                                if (index <= byMonthArray.size) {
                                    if (i == 0) {
                                        rule.append(";BYMONTH=${byMonthArray[index]}")
                                    } else {
                                        rule.append(",${byMonthArray[index]}")
                                    }
                                }
                            }
                        }
                    }
                }

自定義重覆有重覆評率,跟日期類型,自定義時間,比如每個月的1號重覆

上面邏輯是判斷自定義類型 customRepeatFreq,選擇的是日,周,月,年,然後是自定義重覆數 customRepeatInterval,最後是自定義日期 customRepeatItems,具體選擇的某天或者某幾天。

所以把系統規定好的標識都定義成集合,方便動態添加

 

    // BYDAY 周
    private val byDayArray = arrayOf("MO", "TU", "WE", "TH", "FR", "SA", "SU")

    // BYMONTHDAY 月-天
    private val byMonthDayArray = arrayOf(
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
    )

    // BYMONTH 年-月
    private val byMonthArray = arrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
View Code

重點就是在於規範的拼接,需要跟業務結合,然後同步到系統

 

然後是修改日曆,這邊修改也比較繁瑣,並且重覆日曆修改沒有系統那種關聯性,系統可以識別一樣的標題同步修改,程式只能自己迴圈修改,並且每次修改都要獲取許可權,相容性結合業務不好操作,所以綜合考慮,採取先刪除在添加

 

而且居然需要修改,肯定對之前的提醒不滿意,在次添加新的提醒也符合用戶習慣。

日曆操作對時間格式要求高,需要規定好時間格式,加強判斷。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 初識 DEV C++ 首先小衚衕學自己並不是科班出身,不是電腦或者互聯網相關專業的的學生,我本科期間是車輛工程專業,偏機械一點。 本科期間對編程語言的唯一認識就是C,其實也不算是,準確的是DEV C++,但大家都懂得,本科的通識課是可以忽略不計的。 再之後就到了研究生學校這邊,考研的時候就想著能跳 ...
  • 目錄 一、前景回顧 二、實現中斷框架 三、代碼實現 四、中斷的壓棧和出棧過程分析 五、運行測試 一、前景回顧 前面我們已經講解了中斷的基本知識,接下來要開始進行代碼的實操。代碼主要有兩塊,其中一塊是關於可編程中斷控制器8259A的代碼,另一塊主要是整個中斷的代碼。 二、實現中斷框架 IDT:中斷描述 ...
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 Ubuntu20.04伺服器版安裝 下載地址:https://ubuntu.com/download/desktop 一、語言選擇:English(按Done確認,Done按鈕在安裝視窗的最下麵) 二、Installer update avail ...
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 OneForAll是一款功能強大的子域收集工具 我安裝到了kali git clone https://gitee.com/shmilylty/OneForAll.git git clone https://github.com/shmilylt ...
  • 本文會介紹如何安裝和部署ClickHouse,官方推薦的幾種安裝模式,以及安裝之後如何啟動,ClickHouse集群如何配置等。 簡單來說,ClickHouse的搭建流程如下: 環境檢查,環境依賴安裝 在對應的服務上下載安裝Click House 配置config.xml和user.xml,如果搭建 ...
  • mysql拆分字元串作為查詢條件 有個群友問一個問題 這表的ancestors列存放的是所有的祖先節點,以,分隔 例如我查詢dept_id為103的所有祖先節點,現在我只有一個dept_id該怎麼查 然後我去網上找到這樣一個神奇的sql,改改表名就成了下麵的這樣 SELECT substring_i ...
  • 在如今的業務場景下,高可用性要求越來越高,核心業務跨可用區已然成為標配。騰訊雲資料庫高級工程師劉家文結合騰訊雲資料庫的內核實戰經驗,給大家分享Redis是如何實現多可用區,內容包含Redis主從版、集群版原生架構,騰訊雲Redis集群模式主從版、多AZ架構實現以及多AZ關鍵技術點,具體可分為以下四個 ...
  • 本文主要介紹無損壓縮圖片的概要流程和原理,以及lepton無損壓縮在前期調研中遇到的問題。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...