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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...