ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Android Calendar 系统日历提醒、日程同步系统

2022-07-05 20:31:42  阅读:390  来源: 互联网

标签:val 系统 CalendarContract value rule put Android FREQ Calendar


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

首先有个需求(仿制 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

重点就是在于规范的拼接,需要跟业务结合,然后同步到系统

 

然后是修改日历,这边修改也比较繁琐,并且重复日历修改没有系统那种关联性,系统可以识别一样的标题同步修改,程序只能自己循环修改,并且每次修改都要获取权限,兼容性结合业务不好操作,所以综合考虑,采取先删除在添加

 

而且居然需要修改,肯定对之前的提醒不满意,在次添加新的提醒也符合用户习惯。

日历操作对时间格式要求高,需要规定好时间格式,加强判断。

 

标签:val,系统,CalendarContract,value,rule,put,Android,FREQ,Calendar
来源: https://www.cnblogs.com/LiuZhen/p/16445297.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有