对Android手机系统日历数据增删改查操作详解

Android手机系统日历数据增删改查详解

前段时间需要开发提取手机系统的日历数据的功能,自己开始研究了一下,刚开始还是比较懵逼的,经过仔细研究还是能够完全贯通了。

如果不想细细研究,可以直接下载我的Demo运行看效果,改改页面。或者先运行我的apk文件看看是否符合你的要求。
App下载地址;https://www.pgyer.com/WZCalendar
或者扫描下载:
1
要用浏览器扫描,或者应用市场的摄像头扫描下载,如果用微信扫描会提示你打开浏览器下载。

一.手机系统日历数据增删改查基础知识

想要对手机系统日历程序的数据进行增删改查其实不难,只要掌握一些基础知识加上简单的Android开发知识就可以完全掌握了。

1.对系统日历数据操作的原理

对手机系统日历数据的操作,其实就是对系统内的日历程序对应的数据库进行操作,并且系统日历开放了内容提供者,
如果你对内容提供者熟悉,使用内容提供者进行操作,就可以对系统日历数据库的数据进行操作。

2.系统日历数据知识

(1)Android手机系统的日历Google API详解:

https://developer.android.com/guide/topics/providers/calendar-provider?hl=zh-cn

上面这个网址有我们想要知道级大部分知识并且是中文版的,比如几个日历相关的Uri地址,还有日历增删改查的实现简单代码。

上面虽然是官网中的API介绍,但是一样有坑!比如使用它介绍的代码来插入日历数据就崩溃!

主要是一个日历事件id的说明,官网都没有说对,误导很多人。

我看了下,网上其他文章也很少有说对的。

下面还是简单介绍一下手机系统日历的知识:

(2)手机系统日历操作需要添加权限才能操作
  <uses-permission android:name="android.permission.READ_CALENDAR" />
  <uses-permission android:name="android.permission.WRITE_CALENDAR" />

并且这两个权限是隐私权限,在Android6.0后需要动态申请

(3)手机系统日历相关的表和url地址

手机日历程序相关的数据库表有五个,但是真正用到的就一两个。events是最重要的。

表名说明
calendars此表储存日历特定信息。 此表中的每一行都包含一个日历的详细信息,例如名称、颜色、同步信息等。
events此表储存事件特定信息。 此表中的每一行都包含一个事件的信息 — 例如事件标题、地点、开始时间、结束时间等。 事件可一次性发生,也可多次重复发生。参加者、提醒和扩展属性存储在单独的表内。它们各自具有一个 EVENT_ID,用于引用 Events 表中的 _ID。
instances此表储存每个事件实例的开始时间和结束时间。 此表中的每一行都表示一个事件实例。 对于一次性事件,实例与事件为 1:1 映射。对于重复事件,会自动生成多个行,分别对应多个事件实例。
attendees此表储存事件参加者(来宾)信息。 每一行都表示事件的一位来宾。 它指定来宾的类型以及事件的来宾出席响应。
reminders此表储存提醒/通知数据。 每一行都表示事件的一个提醒。一个事件可以有多个提醒。 每个事件的最大提醒数量在 MAX_REMINDERS 中指定,后者由拥有给定日历的同步适配器设置。 提醒以事件发生前的分钟数形式指定,其具有一个可决定用户提醒方式的方法。

关于各个表的使用官网API中都有简单介绍。
其中,如果我们只是对日历日程数据进行增删改查,只需要events者一个表,就足够了,但是如果需要对事件进行提醒就需要对reminders表进行数据插入。

events表的数据就是我们在系统日历中看到的数据,

remianders表的数据,设置了之后,在我们设定的时间会有通知栏的消息,提醒我们。

那个各个表格对于的url地址是什么呢?

 private static String CALANDER_EVENT_URL = "";// 为了兼容不同版本的日历,2.2以后url发生改变
 private static String CALANDER_URL = "";
 private static String CALANDER_REMIDER_URL = "";
 private void initUrl() {
        if (Integer.parseInt(Build.VERSION.SDK) >= 8) {
            CALANDER_URL = "content://com.android.calendar/calendars";
            CALANDER_EVENT_URL = "content://com.android.calendar/events";
            CALANDER_REMIDER_URL = "content://com.android.calendar/reminders";
        } else {
            CALANDER_URL = "content://calendar/calendars";
            CALANDER_EVENT_URL = "content://calendar/events";
            CALANDER_REMIDER_URL = "content://calendar/reminders";
        }

    }

可以看到表格的前缀都是一样的,重要替换后面的表格名字就可以了。
并且现在用的SDK基本不可能小于8,直接用最新的地址是不会有问题的。

手机系统日历程序的文件目录地址: ~/data/data/com.android.calendar/
~表示根目录
但是,我们是没有权限对里面的数据库文件直接拿出来或者替换!root权限是不够的。必须还有系统用户管理员权限。
我们只能根据它暴露的内容提供者的接口来对这几个数据库进行操作。

(4)下面对events表进行详细介绍

events(事件)表,是最重要的一个表,其他的表如果有需要可以看官网API。
表格对应的属性:

常量说明
_ID事件所属日历的 _ID。
CALENDAR_ID事件的固定ID。
ORGANIZER事件组织者(所有者)的电子邮件。
TITLE事件的标题。
EVENT_LOCATION事件的发生地点。
DESCRIPTION事件的描述。
DTSTART事件开始时间,以从公元纪年开始计算的协调世界时毫秒数表示。
DTEND事件结束时间,以从公元纪年开始计算的协调世界时毫秒数表示。
EVENT_TIMEZONE
EVENT_END_TIMEZONE事件结束时间的时区。
DURATIONRFC5545格式的事件持续时间。例如,值为 “PT1H” 表示事件应持续一小时,值为 “P2W” 表示持续 2 周。
ALL_DAY值为 1 表示此事件占用一整天(按照本地时区的定义)。 值为 0 表示它是常规事件,可在一天内的任何时间开始和结束。
RRULE事件的重复发生规则格式。例如,”FREQ=WEEKLY;COUNT=10;WKST=SU”。 您可以在此处找到更多示例。
RDATE事件的重复发生日期。 RDATE 与 RRULE 通常联合用于定义一组聚合重复实例。 如需查看更详细的介绍,请参阅 RFC5545 规范。

上面是官网对events表的属性介绍,需要注意下面几点:

4—1.上面属性在表格中都是小写的,在类调用中才大写而已。
4—2.上面关于id的介绍,我做了一下更正,_id才是事件的id,官网中没有介绍_id,只介绍了calendar_id说这个属性是事件的id。

但是你打印出所有属性的值,就会发现_id才是递增的数值,calendar_id是固定值1,所以官网介绍有误。
后面需要对事件的删除,修改也是使用_id这个属性值,而官网中多次错用了calendar_id这个属性。

4—3.时间

事件开始的事件和结束的时间获取到都是毫秒数的字符串,把它装换为Long在转换为事件字符串就可以得到时间格式的字符串。
时区我感觉没有必要研究。

4—4.关于duration持续时间

如果不是一个重复事件(比如每天,每周,每月等等),那么duration返回的数值都是null
如果是重复事件,那么事件的结束时间就是null

通过几次打印,我发现duration返回的字符形式都是PxxxS,xxx有可能很大几天(需要自己换算成具体的时间),xxx也可能很小,比如半小时为1800

4—5.关于重复规则rrule

通过多次打印并没有发现rdate这个属性有什么作用!

rrule但是有些复杂,如果需要可以深入研究一下,下面是我设置时间打印出来的字符,供大家参考:

日历中的rrule
每周的提醒:
rrule : FREQ=WEEKLY;WKST=SU;BYDAY=MO

每月的提醒:
rrule : FREQ=MONTHLY;WKST=SU;BYMONTHDAY=4//?

每年的提醒:
rrule : FREQ=YEARLY;WKST=SU



每天的提醒
rrule :FREQ=DAILY;WKST=SU

每十天的提醒:
rrule : FREQ=DAILY;INTERVAL=10;WKST=SU

5天
rrule='FREQ=DAILY;INTERVAL=5;WKST=SU'8天提醒一次,截止到20180808
rrule='FREQ=DAILY;UNTIL=20180808T093000;INTERVAL=8;WKST=SU'8天提醒一次,提醒9次
rrule='FREQ=DAILY;COUNT=9;INTERVAL=8;WKST=SU'

我们需要自己根据得到的字符串,解析这个通知的重复规律。
如果需要也可以看看我实例代码中的处理,我是直接硬处理做的,利用String类对字符串进行分割,如果用json解析应该也是可以的。

4—6.events中重要的属性

个人觉得就下面几个:_id,title,dtstart,dtend,event_location,duration,rrule
其他的属性基本用处不大,有具体需要可以看API。

3.关于对手机系统日历数据的增删改查操作简单说明

官网API的代码,有的运行不起来,可以参考我实例中的代码。也可以先看官网的,测试一下。

(1)增加日历事件
String calID = "1";
long startMillis = 0;
long endMillis = 0;
Calendar beginTime = Calendar.getInstance();
beginTime.set(2012, 9, 14, 7, 30);
startMillis = beginTime.getTimeInMillis();
Calendar endTime = Calendar.getInstance();
endTime.set(2012, 9, 14, 8, 45);
endMillis = endTime.getTimeInMillis();
...

ContentResolver cr = getContentResolver();
ContentValues values = new ContentValues();
values.put(Events.DTSTART, startMillis);
values.put(Events.DTEND, endMillis);
values.put(Events.TITLE, "Jazzercise");
values.put(Events.DESCRIPTION, "Group workout");
values.put(Events.CALENDAR_ID, calID);
values.put(Events.EVENT_TIMEZONE, "America/Los_Angeles");
Uri uri = cr.insert(Events.CONTENT_URI, values);          //插入数据的实际操作

// get the event ID that is the last element in the Uri
long eventID = Long.parseLong(uri.getLastPathSegment());
//
// ... do something with event ID,比如添加提醒事件(往提醒表添加数据),或者其他事件

上面Events.CONTENT_URI对应的地址就是events表的url地址对应的Uri对象。
添加事件必须添加事件的calendar_id,title,dtstart,这三个数据,其他数据可以根据需要添加。
calendar_id的值设置为1,是可以添加日历事件的,如果随便一个数值就会报错。。。可以自己测试
calendar_id也并不一定要设为1,也可以设置为_id的第一个值,如果没有删数据就是1,如果删了第一个事件_id的值就是2,以此类推。
calendar_id一定要设置正确,只能是上面的两种情况,设置错误就是报错。

上面插入数据完成后,得到的eventID的值,其实就是表中_id的值,

(2)删除日历事件

long ID = 20; //这个id一定是要表中_id的值,不能是calendar_id的值。
...
ContentResolver cr = getContentResolver();
ContentValues values = new ContentValues();
Uri deleteUri = null;
deleteUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
int rows = getContentResolver().delete(deleteUri, null, null);
Log.i(DEBUG_TAG, "Rows deleted: " + rows);

row大于0就表示删除数据成功。

(3)修改日历事件
long ID = 188; //这个id一定是要表中_id的值,不能是calendar_id的值

ContentResolver cr = getContentResolver();
ContentValues values = new ContentValues();
Uri updateUri = null;
// The new title for the event
values.put(Events.TITLE, "Kickboxing");
updateUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
int rows = getContentResolver().update(updateUri, values, null, null);
Log.i(DEBUG_TAG, "Rows updated: " + rows);  

根据需求可以修改多个数据
同样rows大于零就表示修改成功。

(4)查询日历事件,这也是最重要的操作

前提是你要自己插入一条数据以上。

有些人想要研究日历表格,但是又不能复制里面的数据库出来,那怎么才能详细看到这个表格的所有属性呢。

你可以用下面几句代码遍历出整个表格中所有的属性值:
        String CALANDER_EVENT_URL = "content://com.android.calendar/events";
        Uri uri = Uri.parse(CALANDER_EVENT_URL);
        Cursor cursor = getContentResolver().query(uri, null, null, null, null);
        while (cursor.moveToNext()) {

            int columnCount = cursor.getColumnCount();
            Log.e(TAG, "columnCount :" + columnCount);//多少个属性
            for (int i = 0; i < columnCount; i++) {
                //获取到属性的名称
                String columnName = cursor.getColumnName(i);
                //获取到属性对应的值
                String message = cursor.getString(cursor.getColumnIndex(columnName));
                //打印属性和对应的值
                Log.e(TAG, columnName + " : " + message);

            }
        }   

这时,你可以清楚看到_id和calendar_id的值的区别。

这里演示一下查询主要数据的代码:
        String CALANDER_EVENT_URL = "content://com.android.calendar/events";
        Uri uri = Uri.parse(CALANDER_EVENT_URL);
        Cursor cursor = getContentResolver().query(uri, null, null, null, null);
        while (cursor.moveToNext()) {

            //事件的ID
            String id = cursor.getString(cursor.getColumnIndex(Events._ID)); //不同于Events.CALENDAR_ID
            //事件的标题
            String title = cursor.getString(cursor.getColumnIndex(Events.TITLE));
            //事件的起始时间
            String dtstart = cursor.getString(cursor.getColumnIndex(Events.DTSTART));
            //事件的结束时间 ,如果事件是每天/周,那么就没有结束时间
            String dtend = cursor.getString(cursor.getColumnIndex(Events.DTEND));
            //事件的描述
            String description = cursor.getString(cursor.getColumnIndex(Events.DESCRIPTION));
            //事件的重复规律
            String rrule = cursor.getString(cursor.getColumnIndex(Events.RRULE));
            //事件的复发日期。通常RDATE要联合RRULE一起使用来定义一个重复发生的事件的合集。
            String rdate = cursor.getString(cursor.getColumnIndex(Events.RDATE));
            //事件是否是全天的
            String allDay = cursor.getString(cursor.getColumnIndex(Events.ALL_DAY));
            //事件的地点
            String location = cursor.getString(cursor.getColumnIndex(Events.EVENT_LOCATION));
            //事件持续时间,例如“PT1H”表示事件持续1小时的状态, “P2W”指明2周的持续时间。P3600S表示3600秒
            String duration = cursor.getString(cursor.getColumnIndex(Events.DURATION));

            //other
            String last_date = cursor.getString(cursor.getColumnIndex(Events.LAST_DATE));
            String original_id = cursor.getString(cursor.getColumnIndex(Events.ORIGINAL_ID));
            String maxReminders = cursor.getString(cursor.getColumnIndex(Events.MAX_REMINDERS));
            String allowedReminders = cursor.getString(cursor.getColumnIndex(Events.ALLOWED_REMINDERS));

        。。。

        }
(5)其他的

一般来说,对日历的操作无非是添加或查询,其他操作是很少用到的。
比如,我Log了一下自己的日历事件,发现很多信用卡提示,火车票提示,淘宝自己设的活动提示的事件等等信息。

获取日历数据App程序的效果

1.主页

直接显示查询到手机所有的日历行程数据
2

2.增删改查页面

3

3.增删改查操作

修改操作:
4
我这里只是简单演示效果,如果需要可以修改多个数据。

删除操作:
4

4.项目的源码

https://download.csdn.net/download/wenzhi20102321/10470759

这个获取手机系统日历的程序就介绍到这里,有用的人可以看看,试试。

共勉:你的努力能决定很多事情。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

峥嵘life

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值