安卓调用日历提醒,并实现闹钟提醒功能,在miui上测试通过,日历提醒闹钟设置失败解决(附源码,源码已更新)

不想看教程的可以直接走这里的后门去下载源码(源码已更新),源码小米手机亲测通过,有问题可以私信我:源码下载https://download.csdn.net/download/Spy003/87418013

不想下载,那就接着往下看教程,教程有点多,请耐心阅读。

项目有个新需求,就是app需要调用插入安卓系统日历日程提醒,过程中遇到了不少问题,先来看看如何实现向日历中插入日程提醒:

1、首先实现插入日程提醒,上关键代码

    private static String CALENDARS_NAME = "Time Bag";
    private static String CALENDARS_ACCOUNT_NAME = "Time Bag";
    private static String CALENDARS_ACCOUNT_TYPE = "com.example.timebag";
    /**
     * 这里创建账户的展示名称,系统日历为我们提供了创建账户的入口,那我们就不使用系统自带的账户,创建一个自己app的账户
     */
    private static String CALENDARS_DISPLAY_NAME = "时间锦囊";

    /**
     * 检查是否已经添加了日历账户,如果没有添加先添加一个日历账户再查询
     * 获取账户成功返回账户id,否则返回-1
     */
    @RequiresApi(api = Build.VERSION_CODES.N)
    private static int checkAndAddCalendarAccount(Context context) {
        int oldId = checkCalendarAccount(context);
        if (oldId >= 0) {
            return oldId;
        } else {
            long addId = addCalendarAccount(context);
            if (addId >= 0) {
                return checkCalendarAccount(context);
            } else {
                return -1;
            }
        }
    }

    /**
     * 检查是否存在现有账户,存在则返回账户id,否则返回-1
     */
    @SuppressLint("Range")
    private static int checkCalendarAccount(Context context) {
        Cursor userCursor = context.getContentResolver().query(CalendarContract.Calendars.CONTENT_URI, null, null, null, null);
        try {
            if (userCursor == null) { //查询返回空值
                return -1;
            }
            int count = userCursor.getCount();
            if (count > 0) { //存在现有账户,取第一个账户的id返回
                for (int i = 0;i<=count-1;i++){
                    if (i==0){
                        userCursor.moveToFirst();
                    } else {
                        userCursor.moveToNext();
                    }
                    String type = userCursor.getString(userCursor.getColumnIndex(CalendarContract.Calendars.ACCOUNT_TYPE));
                    if (type.equals(CALENDARS_ACCOUNT_TYPE)) {
                        return userCursor.getInt(userCursor.getColumnIndex(CalendarContract.Calendars._ID));
                    }
                }
            }
            return -1;
        } finally {
            if (userCursor != null) {
                userCursor.close();
            }
        }
    }


    /**
     * 添加日历账户,账户创建成功则返回账户id,否则返回-1
     */
    private static long addCalendarAccount(Context context) {
        TimeZone timeZone = TimeZone.getDefault();
        ContentValues value = new 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);

        Uri calendarUri = CalendarContract.Calendars.CONTENT_URI;
        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();

        Uri result = context.getContentResolver().insert(calendarUri, value);
        long id = result == null ? -1 : ContentUris.parseId(result);
        return id;
    }

    /**
     * 这个是关键方法,调用插入日程提醒
     * @param context
     * @param title 提醒事件标题
     * @param description 事件描述
     * @param reminderTime 任务开始时间,这里参数名不太合适,后面会加提醒时间,
     * @param endTime 任务结束时间
     * @param previousMinutes 提前多少分钟提醒,后续使用
     */
    @RequiresApi(api = Build.VERSION_CODES.N)@SuppressLint("Range")
    public static void addCalendarEvent(Context context, String title, String description, long reminderTime, long endTime, int previousDate) {
        if (context == null) {
            return;
        }
        int calId = checkAndAddCalendarAccount(context); //获取日历账户的id
        if (calId < 0) { //获取账户id失败直接返回,添加日历事件失败
            return;
        }

        //添加日历事件
        Calendar mCalendar = Calendar.getInstance();
        mCalendar.setTimeInMillis(reminderTime);//设置开始时间
        long start = mCalendar.getTime().getTime();
        mCalendar.setTimeInMillis(endTime);//设置终止时间
        long end = mCalendar.getTime().getTime();
        ContentValues event = new ContentValues();
        event.put("title", title);
        event.put("description", description);
        event.put("calendar_id", calId); //插入账户的id
        event.put("eventStatus", 1);
        event.put(CalendarContract.Events.HAS_EXTENDED_PROPERTIES,true);
        event.put(CalendarContract.Events.DTSTART, start);
        event.put(CalendarContract.Events.DTEND, end);
        event.put(CalendarContract.Events.HAS_ALARM, 1);//设置有闹钟提醒,但是经测试,此方案无效
        event.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().getDisplayName());//这个是时区,必须有
        Uri newEvent = context.getContentResolver().insert(CalendarContract.Events.CONTENT_URI, event); //添加事件
        if (newEvent == null) { //添加日历事件失败直接返回
            return;
        }

        //事件提醒的设定
        ContentValues values = new ContentValues();
        values.put(CalendarContract.Reminders.EVENT_ID, ContentUris.parseId(newEvent));
        values.put(CalendarContract.Reminders.MINUTES, 0);// 提前previousDate天有提醒
        values.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT);
        Uri uri = context.getContentResolver().insert(CalendarContract.Reminders.CONTENT_URI, values);
        if (uri == null) { //添加事件提醒失败直接返回
            return;
        }

    }

到这里,我们调用 addCalendarEvent() 方法就可以实现创建了,这个方法有若干个参数,如果有需要还可以加,我们看到,其实创建日程提醒,就是执行了两次 insert 的数据库插入操作,插入的表分别是events和reminders。这里的调用是用了kotlin的写法,日期是毫秒数,开始时间加了10s,这样可以实现插入完成以后10s我们就能看到提醒。

addCalendarEvent(content,'测试插入日历标题','这是测试内容',(Date().time+10000),(Date().time+30000))

到这里我们就看到有日历通知了,而且是弹窗通知。但是这里有问题,就是我们的需求是实现闹钟提醒,我们看到在插入reminders表的时候,有一个字段叫hasAlarm,这个字段就是谷歌给留出来用于开启是否使用闹钟提醒的,但是这个字段明显没有用了,也许是年久失修吧,而且这里的资料少之又少,我摸索了两天,通过对安卓日历数据表的对比,才发现了关键,那就是日历提醒还设计另一个表,名字叫 ExtendedProperties ,这个表一共三个字段,这三个字段都很重要,都需要设置,event_id字段是用来绑定event事件的,这个id上面用到了,直接传进来就行。name字段也很重要,而且不能设置其他,否则也一样无法开启闹钟,value字段就直接决定是否开启闹钟了,直接看代码:

        //扩展属性,这个表有三个字段,更新以后的安卓系统对于三个字段的值都有要求,源码处有更新,有疑问也可以评论或者私聊,我全部无条件回复
        Uri extendedPropUri = CalendarContract.ExtendedProperties.CONTENT_URI;
        extendedPropUri = extendedPropUri.buildUpon()
                .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER,"true")
                .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_NAME, CALENDARS_ACCOUNT_NAME)
                .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_TYPE, CALENDARS_ACCOUNT_TYPE).build();
        ContentValues extendedProperties = new ContentValues();
        extendedProperties.put(CalendarContract.ExtendedProperties.EVENT_ID,ContentUris.parseId(newEvent));
        extendedProperties.put(CalendarContract.ExtendedProperties.VALUE,"{\"need_alarm\":true}");
        Uri uriExtended = context.getContentResolver().insert(extendedPropUri, extendedProperties);
        if (uriExtended == null) { //添加事件提醒失败直接返回
            return;
        }

然后到这里就实现了闹钟的添加,闹钟响起来了,我的心情也好起来了

不知道你会了没,如果嫌教程太麻烦,那就直接来下载源码吧,源码中还有一些周边方法,比如 遍历查看安卓数据库所有行列 条目内容的方法。源码小米手机亲测通过,有问题可以私信我:

源码下载https://download.csdn.net/download/Spy003/87418013

总结一下就是:设置日历弹窗提醒,只需要按照我上面说的,对events和reminders表进行插入就ok,如果需要开启闹钟的话,就需要插入第三个表ExtendedProperties。

提醒效果见下图:

 源码下载https://download.csdn.net/download/Spy003/87418013

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值