Android 日历表事件表操作

Android日历操作

基础知识

内容提供程序用于存储数据,并使其可供应用访问。Android 平台提供的内容提供程序(包括日历提供程序)通常以一组基于关系型数据库模型的表格形式公开数据,表格内的每一行都是一条记录,每一列都是特定类型和含义的数据。应用和同步适配器可通过 Calendar Provider API 获得对储存用户日历数据的数据库表进行读取/写入的权限。

每个内容提供程序都会公开一个公共 URI(包装成 Uri 对象),从而对其数据集进行唯一标识。控制多个数据集(多个表)的内容提供程序会为每个数据集公开单独的 URI。所有提供程序 URI 都以字符串“content://”开头。这表示数据会受内容提供程序的控制。日历提供程序会为其每个类(表)定义 URI 常量。这些 URI 的格式为 *<class>*.CONTENT_URI。例如,Events.CONTENT_URI

image-20220526203100599

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

用户权限

如果需要读取日历数据,需要加入READ_CALENDAR 权限。若需要对日历数据进行删改操作,需要WRITE_CALENDAR权限:

<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />

  
  

日历表

CalendarContract.Calendars 表包含各日历的详细信息。应用和同步适配器均可写入以下日历列。

常量描述
NAME日历的名称。
CALENDAR_DISPLAY_NAME显示给用户时,该日历所使用的名称。
VISIBLE表示是否选择显示该日历的布尔值。值为 0 表示不应显示与该日历关联的事件。值为 1 表示应该显示与该日历关联的事件。此值会影响 CalendarContract.Instances 表中行的生成。
SYNC_EVENTS一个布尔值,表示是否应同步日历并将其事件存储在设备上。值为 0 表示不同步该日历,也不将其事件存储在设备上。值为 1 表示同步该日历的事件,并将其事件存储在设备上。

包括适用于所有操作的账户类型

如果您查询 Calendars.ACCOUNT_NAME,还必须将 Calendars.ACCOUNT_TYPE 加入选定范围。原因是对于给定帐户,只有在同时指定其 ACCOUNT_NAMEACCOUNT_TYPE 的情况下,才能将其视为唯一帐户。ACCOUNT_TYPE 字符串对应在 AccountManager 处注册帐户时所使用的帐户验证器。还有一种称为 ACCOUNT_TYPE_LOCAL 的特殊帐户类型,其用于未关联设备帐户的日历。ACCOUNT_TYPE_LOCAL 帐户不会进行同步。

日历操作

查询日历

原则上该操作需要在非主线程中完成。

// Projection array. Creating indices for this array instead of doing
// dynamic lookups improves performance.
public static final String[] EVENT_PROJECTION = new String[] {
    Calendars._ID,                           // 0
    Calendars.ACCOUNT_NAME,                  // 1
    Calendars.CALENDAR_DISPLAY_NAME,         // 2
    Calendars.OWNER_ACCOUNT                  // 3
};
// The indices for the projection array above.
private static final int PROJECTION_ID_INDEX = 0;
private static final int PROJECTION_ACCOUNT_NAME_INDEX = 1;
private static final int PROJECTION_DISPLAY_NAME_INDEX = 2;
private static final int PROJECTION_OWNER_ACCOUNT_INDEX = 3;
// Run query
Cursor cur = null;
ContentResolver cr = getContentResolver();
Uri uri = Calendars.CONTENT_URI;
String selection = "((" + Calendars.ACCOUNT_NAME + " = ?) AND ("
                        + Calendars.ACCOUNT_TYPE + " = ?) AND ("
                        + Calendars.OWNER_ACCOUNT + " = ?))";
String[] selectionArgs = new String[] {"hera@example.com", "com.example",
        "hera@example.com"};
// Submit the query and get a Cursor object back.
cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);
// Use the cursor to step through the returned records
while (cur.moveToNext()) {
    long calID = 0;
    String displayName = null;
    String accountName = null;
    String ownerName = null;
    // Get the field values
    calID = cur.getLong(PROJECTION_ID_INDEX);
    displayName = cur.getString(PROJECTION_DISPLAY_NAME_INDEX);
    accountName = cur.getString(PROJECTION_ACCOUNT_NAME_INDEX);
    ownerName = cur.getString(PROJECTION_OWNER_ACCOUNT_INDEX);
    // Do something with the values...
   ...
}

如果查询之后发现没有日历,那就需要先创建一个日历账户。

    public static void createCalendar(Context context){
        TimeZone timeZone = TimeZone.getDefault();
        ContentValues values = new ContentValues();
        values.put(CalendarContract.Calendars.NAME, "yiyi");
        values.put(CalendarContract.Calendars.ACCOUNT_NAME, "1138154255@qq.com");
        values.put(CalendarContract.Calendars.ACCOUNT_TYPE, "com.android.exchange");
        values.put(CalendarContract.Calendars.VISIBLE, 1);
        values.put(CalendarContract.Calendars.CALENDAR_COLOR, -9206951);
        values.put(CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL, CalendarContract.Calendars.CAL_ACCESS_OWNER);
        values.put(CalendarContract.Calendars.SYNC_EVENTS, 1);
        values.put(CalendarContract.Calendars.CALENDAR_TIME_ZONE, timeZone.getID());
        values.put(CalendarContract.Calendars.OWNER_ACCOUNT, "1138154255@qq.com");
        values.put(CalendarContract.Calendars.CAN_ORGANIZER_RESPOND, 0);
        values.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, "KiLin");
        Uri calendarUri = CalendarContract.Calendars.CONTENT_URI;
        calendarUri = calendarUri.buildUpon()
                .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true")
                .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_NAME, "1138154255@qq.com")
                .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_TYPE, "com.android.exchange")
                .build();
        context.getContentResolver().insert(calendarUri, values);
    }

如上可以创建一个日历账户,其中的参数可以自己进行定义。

如果需要修改日历,比如修改一下日历的DISPLAY_NAME:

        //修改日历表
        ContentValues values = new ContentValues();
        values.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, "KiLin");
        Uri updateUri = ContentUris.withAppendedId(CalendarContract.Calendars.CONTENT_URI, 1);
        int rows = getContentResolver().update(updateUri, values, null, null);
        Log.d(TAG, String.valueOf(rows));

 
 

事件表

CalendarContract.Events 表包含各事件的详细信息。如要添加、更新或删除事件,则应用必须在其清单文件中加入 WRITE_CALENDAR 权限。

应用和同步适配器均可写入以下事件列。如需查看所支持字段的完整列表,请参阅 CalendarContract.Events 参考资料。

常量描述
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事件的重复发生日期。RDATERRULE 通常联合用于定义一组存在聚合关系的重复实例。如需查看更详细的介绍,请参阅 RFC5545 规范
AVAILABILITY将此事件视为忙碌时间还是可调度的空闲时间。
GUESTS_CAN_MODIFY来宾是否可修改事件。
GUESTS_CAN_INVITE_OTHERS来宾是否可邀请其他来宾。
GUESTS_CAN_SEE_GUESTS来宾是否可查看参加者列表。

添加事件

当应用插入新事件时,我们建议您按使用 Intent 插入事件中所述使用 INSERT Intent。不过,如有需要,您也可直接插入事件。本部分描述如何执行此操作。

以下是插入新事件的规则:

  • 您必须加入 CALENDAR_IDDTSTART
  • 您必须加入 EVENT_TIMEZONE。如需获取系统中已安装时区 ID 的列表,请使用 getAvailableIDs()。请注意,如果您按使用 Intent 插入事件中所述通过 INSERT Intent 插入事件,则此规则不适用 — 在该情形下,系统会提供默认时区。
  • 对于非重复事件,您必须加入 DTEND
  • 对于重复事件,您必须加入 DURATION,以及 RRULERDATE。请注意,如果您按使用 Intent 插入事件中所述通过 INSERT Intent 插入事件,则此规则不适用 — 在该情形下,您可以将 RRULEDTSTARTDTEND 结合使用,日历应用会自动将其转换为持续时间。

以下是一个插入事件的示例。为简便起见,我们在界面线程内执行此操作。实际上,应该在异步线程中完成插入和更新,以便将操作移入后台线程。如需了解详细信息,请参阅 AsyncQueryHandler

@RequiresApi(api = Build.VERSION_CODES.N)
    public static void insertEvent(Context context, long calID){
        Calendar beginTime = Calendar.getInstance();
        beginTime.set(2022, 5, 1, 22, 0);
        long startMillis = beginTime.getTimeInMillis();
        Calendar endTime = Calendar.getInstance();
        endTime.set(2022, 5, 1, 23, 30);
        long endMillis = endTime.getTimeInMillis();
        ContentResolver cr = context.getContentResolver();
        ContentValues values = new ContentValues();
        values.put(CalendarContract.Events.DTSTART, startMillis);
        values.put(CalendarContract.Events.DTEND, endMillis);
        values.put(CalendarContract.Events.TITLE, "日历开发");
        values.put(CalendarContract.Events.DESCRIPTION, "增加日历的增删改功能");
        values.put(CalendarContract.Events.CALENDAR_ID, calID);
        values.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().getID());
        Uri uri = cr.insert(CalendarContract.Events.CONTENT_URI, values);
        long eventID = Long.parseLong(uri.getLastPathSegment());
        System.out.println("EventId: " + eventID);
    }

通过上面的案例我们可以看到,修改日历比较重要的一个参数就是日历账户的ID,Android的日历管理是将数据以账户为单位的,没有ID就不知道要对哪一个日历账户进行修改,所以一般在修改日历数据的时候都会先查询是否有存在的日历账户,若是没有则需要先新建一个日历账户,然后再进行日历的增删改查。

更新事件

更新的时候可以使用eventID进行,但是google建议是通过Intent编辑事件进行。

    public static void updateEvent(Context context, long eventID){
        ContentResolver cr = context.getContentResolver();
        ContentValues values = new ContentValues();
        Uri updateUri = null;
        values.put(CalendarContract.Events.TITLE, "日历修改测试");
        updateUri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID);
        int rows = cr.update(updateUri, values, null, null);
        System.out.println("EventsRows: " + rows);
    }

删除事件

当然也可以如类似上文更新事件的方法进行事件的删除。

    public static void deleteEvent(Context context, long eventID){
        ContentResolver cr = context.getContentResolver();
        Uri deleteUri = null;
        deleteUri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID);
        int rows = cr.delete(deleteUri, null, null);
        System.out.println("EventsRows: " + rows);
    }
                

原文链接:https://blog.csdn.net/qq_46015650/article/details/125092272

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值