Android開發-API指南- Calendar Provider


Calendar Provider

英文原文:http://developer.android.com/guide/topics/providers/calendar-provider.html
采集日期:2015-05-10

Calendar Provider 是用來存放用戶日歷事件(event)的數據庫。 通過 Calendar Provider 的 API ,可以完成對 calendars、events、attendees、reminders 表的查詢、插入、修改和刪除等操作。

應用程序和 Sync Adapter 都可以使用 Calender Provider API。 對於這兩種不同類型的程序,調用的規則也不一樣。 本文的重點是介紹應用程序是如何使用 Calender Provider API 的。 Sync Adapter 的使用方式會有所不同,請參閱Sync Adapters

通常,如果要讀寫日歷數據,應用程序必須在 Manifest 文件中聲明相應的權限,這在用戶權限一節中將會介紹。 為了便於完成一些常見的操作, Calender Provider 提供了一些 Intent,這將在Calendar Intent一節中介紹。 這些 Intent 可以讓用戶打開 Calendar 應用,並完成插入、查看、編輯事件的操作。 用戶在 Calendar 應用中完成交互后,將返回初始的應用中。 這樣發起方應用就不必申請相應權限,也不需要提供瀏覽和創建事件的用戶界面了。

基礎知識

Content Provider 負責存放數據並提供數據訪問方式。 Android 系統內置的 Content Provider (包括 Calendar Provider)一般是以關系型數據庫表的形式提供數據的, 行數據代表一條記錄,列數據表示字段類型和意義。 應用程序和 Sync Adapter 通過 Calendar Provider API 來訪問數據庫表中的用戶日歷數據。

每個 Content Provider 都會公開一個公共的 URI (封裝為一個 Uri 對象),它唯一標識了某部分數據。 如果 Content Provider 管理着多組數據(多張數據表),則各組數據都會有單獨的 URI。 所有用於 Provider 的 URI 都以字符串 "content://" 開頭,表示這些數據是由某個 Content Provider 進行管理的。 Calendar Provider 為其內部類(表)的 URI 定義了很多常量。這些 URI 的格式均為 <class>.CONTENT_URI。比如 Events.CONTENT_URI

圖 1 為 Calendar Provider 數據模型的示意圖,給出了主表及與其他表的關聯字段。

圖 1. Calendar Provider 數據模型

一個用戶可以擁有多個 Calendar,每個 Calendar 可以與不同類型的帳號關聯(Google Calendar、Exchange 等)。

CalendarContract 定義了 Calendar 和 Event 的數據模型。這些數據存放在以下數據表中。

數據表(類) 說明

CalendarContract.Calendars

該表存放日程的定義數據。每行表示一條日程的詳細信息,如名稱、顏色、同步信息等。
CalendarContract.Events 該表存放事件的定義數據。每行表示一個事件,內容包括 — 事件標題、位置、起始時間、結束時間等等。 事件可以是一次性的,也可以重復多次觸發。 參與人員、提醒鬧鍾及附加屬性都存放在其他表中,並通過 EVENT_ID 字段與 Events 表中的 _ID 關聯。
CalendarContract.Instances 該表存放事件每次觸發時的起始時間和結束時間。一次性事件只會1:1對應一條實例記錄。 對於重復觸發的事件而言,則會自動生成多條實例記錄,對應每一次的觸發。
CalendarContract.Attendees 該表存放事件的參與人員(來賓)信息。每行代表一位人員。 內容包括人員類型和與會反饋。
CalendarContract.Reminders 該表存放鬧鍾/通知數據。每行代表一次鬧鍾提醒。 一個事件可以擁有多個鬧鍾提醒。每個事件可擁有的最大提醒數在 MAX_REMINDERS 中定義,這是由擁有該日程的 sync adapter 設置的。 提醒定義了事件觸發前的分鍾數,以及提醒用戶的方式。

Calendar Provider API 的設計初衷,是既要靈活又要功能強大。另一方面,良好的用戶體驗、保證日程數據的安全也非常重要。 為此,在使用這些 API 時,必須注意以下幾點:

  • 插入、更新和查詢日程事件。 如果要直接插入、修改和查詢 Calendar Provider 中的事件數據,需要獲得合適的權限。 不過,如果還未建立完整的日歷應用或 Sync Adapter,就沒必要申請這些權限。 這時就可以通過 Intent,把讀寫操作交給 Android 內置 Calendar 應用去完成。 在使用這些 Intent 時,用戶會被帶入 Calendar 應用,在預置的表單中進行操作。待操作完畢后,再返回調用方應用。 通過這種調用內置 Calendar 來完成常用操作的方式,可以向用戶提供一種風格統一、容錯性較強的界面。 這也是推薦的訪問方式。詳情請參閱Calendar Intent
  • Sync Adapter。 Sync Adapter 負責將用戶設備上的日程數據與服務器或數據源保持同步。在 CalendarContract.CalendarsCalendarContract.Events 表中,有些字段是留給 Sync Adapter 使用的。 Provider 和應用程序都不要去修改這些字段中的數據。 實際上只有以 Sync Adapter 的方式去訪問時,這些字段才是可見的。 關於 Sync Adapter 的詳細信息,請參閱 Sync Adapter

用戶權限

如果要讀取日程數據,應用程序必須在 Manifest 文件中包含 READ_CALENDAR 權限。如果是刪除、插入或修改日程數據,則必須包含 WRITE_CALENDAR 權限:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"...>
    <uses-sdk android:minSdkVersion="14" />
    <uses-permission android:name="android.permission.READ_CALENDAR" />
    <uses-permission android:name="android.permission.WRITE_CALENDAR" />
    ...
</manifest>

Calendars 表

CalendarContract.Calendars 表存放着每項日程的詳細信息。 以下字段均可由應用程序和 Sync Adapter 寫入。 完整的字段清單請參閱手冊 CalendarContract.Calendars

常量名稱 說明
NAME 日程的名稱。
CALENDAR_DISPLAY_NAME 向用戶顯示的日程名稱。
VISIBLE 布爾值,標明該日程是否可見。 為 0 表示不顯示與該日程關聯的事件,為 1 則表示需要顯示。 該值將會影響 CalendarContract.Instances 表中生成的記錄。
SYNC_EVENTS 布爾值,標明該日程是否需要同步,及事件是否需要本地保存。 為 0 表示不需要同步或者不保存。為 1 則表示應該同步並在設備中保存事件。

查詢日程

以下例子演示了如何讀取某個用戶的日程信息。 為了簡化起見,查詢操作是在用戶界面線程(“主線程”)中進行的。 在實際應用中,這步操作不應放在主線程中,而應該在異步線程中完成。更多信息,請參閱Loaders。 如果不僅要讀取數據,還要修改的話,請參閱 AsyncQueryHandler

// 映射數組。為數組建立索引,就不需要動態檢索,以便提高性能。
public static final String[] EVENT_PROJECTION = new String[] {
    Calendars._ID,                           // 0
    Calendars.ACCOUNT_NAME,                  // 1
    Calendars.CALENDAR_DISPLAY_NAME,         // 2
    Calendars.OWNER_ACCOUNT                  // 3
};
  
// 映射數組的索引
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;

接下來就是構建查詢,在查詢語句中指定查詢條件。 這里要查詢的日程,ACCOUNT_NAME為“sampleuser@google.com”, ACCOUNT_TYPE為“com.google”,OWNER_ACCOUNT為“sampleuser@google.com”。 如果要查詢某用戶可查看的所有日程,而不僅限於屬於用戶自己的日程,請去掉OWNER_ACCOUNT條件。 查詢將會返回一個 Cursor 對象,通過該游標可以遍歷返回的結果數據集。 關於 Content Provider 查詢的更多介紹,請參閱 Content Provider

// 執行查詢
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[] {"sampleuser@gmail.com", "com.google",
        "sampleuser@gmail.com"}; 
// 提交查詢並獲取結果 Cursor 對象。
cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);

下面通過游標遍歷查詢結果。 這里用到了一開始定義的常量,返回各個字段的數據。

// 利用游標遍歷結果記錄集
while (cur.moveToNext()) {
    long calID = 0;
    String displayName = null;
    String accountName = null;
    String ownerName = null;
      
    // 讀取各個字段的數據
    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);
              
    // 用這些數據進行一些操作...

   ...
}

修改日程

如果要修改日程數據,可以把該項日程的 _ID 作為 URI (withAppendedId()) 的附帶 ID 參數,或者作為第一個查詢條件。 作為查詢條件時,應該以"_id=?"開頭,第一個參數selectionArg應該是該項日程的 _ID。 還可以把 ID 加入 URI 編碼中執行數據更新操作。 以下給出了通過 URI 方式 (withAppendedId()) 修改日程顯示名稱的例子:

private static final String DEBUG_TAG = "MyActivity";
...
long calID = 2;
ContentValues values = new ContentValues();
// 該日程的新名稱
values.put(Calendars.CALENDAR_DISPLAY_NAME, "Trevor's Calendar");
Uri updateUri = ContentUris.withAppendedId(Calendars.CONTENT_URI, calID);
int rows = getContentResolver().update(updateUri, values, null, null);
Log.i(DEBUG_TAG, "Rows updated: " + rows);

插入日程

日程本來就設計為主要由 Sync Adapter 來維護的,因此只能由一個 Sync Adapter 來插入一項新的日程。 多數情況下,應用程序只能對日程做一些外觀上的修改,比如修改顯示名稱。 如果應用程序需要新建一項日程,可以作為 Sync Adapter 來執行插入操作, ACCOUNT_TYPE 設為 ACCOUNT_TYPE_LOCALACCOUNT_TYPE_LOCAL 是一種專為日程設計的特殊賬戶,它不與實際的本地賬戶關聯。 這種日程數據也不會與服務器同步。 關於 Sync Adapter 的介紹,請參閱 Sync Adapter

Events 表

CalendarContract.Events 表存放着每個事件的詳細信息。 如果要新增、修改或刪除事件,應用程序必須在 Manifest 文件 中包含 WRITE_CALENDAR 權限。

以下字段均可由應用程序和 Sync Adapter 寫入。 完整的字段清單,請參閱手冊 CalendarContract.Events

常量 說明
CALENDAR_ID 事件所屬日程的 _ID
ORGANIZER 日程編制者(所有者)的 Email。
TITLE 事件標題。
EVENT_LOCATION 事件所在地。
DESCRIPTION 事件說明。
DTSTART 事件起始 UTC 時間,單位為自1970年1月1日以來的毫秒數。
DTEND 事件結束 UTC 時間,單位為自1970年1月1日以來的毫秒數。
EVENT_TIMEZONE 事件時區。
EVENT_END_TIMEZONE 事件結束時間的時區。
DURATION 事件的持續時間,格式為RFC5545。 比如,"PT1H"表示事件會持續 1 小時,"P2W"則表示持續 2 周。
ALL_DAY 為 1 表示該事件會占用全天時間,類似於時區設置中的定義。 為 0 表示其為常規事件,可以在一天中的任意時刻開始和結束。
RRULE 事件重復規則。比如:"FREQ=WEEKLY;COUNT=10;WKST=SU"。 更多示例請查看 RFC5545
RDATE 事件重復的日期。通常是把 RDATERRULE 結合起來定義一組重復規則。詳情請參閱 RFC5545 說明
AVAILABILITY 標明該事件是在空閑時參與調度,還是在忙時參與。
GUESTS_CAN_MODIFY 來賓是否可以修改事件。
GUESTS_CAN_INVITE_OTHERS 來賓是否可以邀請其他人參加。
GUESTS_CAN_SEE_GUESTS 來賓是否能看到參加人員名單。

添加事件

推薦使用 INSERT 來插入一條新的事件,這在 利用 Intent 插入事件 一節中將會介紹。 不過在必要時,也可以直接插入一條事件記錄。本節將介紹這種方式。

下面列出了插入新事件需要遵守的規則:

下面給出一個插入事件的例子。簡化起見,此例運行於 UI 線程中。 在實際應用中,插入和修改操作都應該在后台的異步線程中完成。詳情請參閱 AsyncQueryHandler

long calID = 3;
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);

// 讀取事件 ID,也就是 Uri 的最后一部分
long eventID = Long.parseLong(uri.getLastPathSegment());
// 
// ... 利用 ID 完成一些處理
//
//

注意: 上述例子中,讀取已創建事件 ID 的方式是一種最簡單的方法。 在實際應用中,往往需要利用事件 ID 來對日程進行某些操作 — 比如:添加參與人員、增加事件提醒。

修改事件

如果需要讓用戶編輯事件,建議使用 EDIT Intent,這在 利用 Intent 編輯事件 一節中將會介紹。 不過在必要時,也可以直接編輯事件。 在修改事件時,給出事件 _ID 的方式可以是附在 Uri 后面( withAppendedId() ),也可以是作為查詢條件的第一個參數。 查詢條件應該以 "_id=?" 開頭,第一個 selectionArg 應該是事件的 _ID 。 也可以使用不帶 ID 的查詢語句來更新數據。 下面給出一個更新事件數據的例子,這里將用 withAppendedId() 的方式修改事件的標題:

private static final String DEBUG_TAG = "MyActivity";
...
long eventID = 188;
...
ContentResolver cr = getContentResolver();
ContentValues values = new ContentValues();
Uri updateUri = null;
// 新的標題
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);  

刪除事件

可以將 _ID 附在 URI 后面進行刪除操作,也可以用標准的查詢語句來完成。 如果采用前一種方式,就不能再用查詢語句的方式。 刪除操作有兩種版本:作為應用程序、作為 Sync Adapter。 應用程序版本的刪除就是把 deleted 字段置為 1。這會告訴 Sync Adapter 此條記錄已被刪除,同時服務器上也應該完成刪除操作。 Sync Adapter 版本的刪除則會在數據庫中刪除該條事件及所有相關數據。 以下例子演示了應用程序版本的刪除,用到了 _ID

private static final String DEBUG_TAG = "MyActivity";
...
long eventID = 201;
...
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);  

Attendees 表

CalendarContract.Attendees 表的每行記錄代表參加事件的一位人員(來賓)。以 EVENT_ID 為參數調用 query() ,將會返回該事件的參加人員清單。這里的 EVENT_ID 必須與事件的實際 _ID一致。

下表列出了 Attendees 表中可供寫入的字段。在插入新的人員記錄時,必須包含除ATTENDEE_NAME外的所有這些字段。

常量名稱 說明
EVENT_ID 事件 ID。
ATTENDEE_NAME 參加人員的姓名。
ATTENDEE_EMAIL 參加人員的 Email 地址。
ATTENDEE_RELATIONSHIP

該人員與事件的關系。可為下列值之一:

ATTENDEE_TYPE

參加人員的類型。可為下列值之一:

ATTENDEE_STATUS

參加人員的出席狀況。可為下列值之一:

添加參加人員

以下給出了添加一個事件參與人員的例子。 請注意必須要給出 EVENT_ID

long eventID = 202;
...
ContentResolver cr = getContentResolver();
ContentValues values = new ContentValues();
values.put(Attendees.ATTENDEE_NAME, "Trevor");
values.put(Attendees.ATTENDEE_EMAIL, "trevor@example.com");
values.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE);
values.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_OPTIONAL);
values.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_INVITED);
values.put(Attendees.EVENT_ID, eventID);
Uri uri = cr.insert(Attendees.CONTENT_URI, values);

Reminders 表

CalendarContract.Reminders 表的每行記錄代表針對某事件的一條系統提醒。以 EVENT_ID 為參數調用 query() 時,將會返回相關系統提醒的清單。

下表列出了 Reminders 表中可供寫入的字段。 在插入一條新的提醒數據時,必須包含所有這些字段。 請注意,在 CalendarContract.Calendars 表中,定義了 Sync Adapter 支持的提醒類型。 詳情請參閱 ALLOWED_REMINDERS

常量名稱 說明
EVENT_ID 事件 ID。
MINUTES 在事件發生之前多少分鍾進行提醒。
METHOD

提醒方式,這是服務器上的設置。可為下列值之一:

添加提醒

下屬例子為某個事件添加了一條提醒。這條提醒將會在事件發生前 15 分鍾觸發。

long eventID = 221;
...
ContentResolver cr = getContentResolver();
ContentValues values = new ContentValues();
values.put(Reminders.MINUTES, 15);
values.put(Reminders.EVENT_ID, eventID);
values.put(Reminders.METHOD, Reminders.METHOD_ALERT);
Uri uri = cr.insert(Reminders.CONTENT_URI, values);

Instances 表

CalendarContract.Instances 表存放着事件的起始和結束時間。 每行記錄代表事件的一次實例。 Instances 是不可寫的,僅用於查詢事件的發生經歷。

下表列出了 Instances 表中可供查詢的部分字段。 請注意時區是由 KEY_TIMEZONE_TYPEKEY_TIMEZONE_INSTANCES 定義的。

常量 說明
BEGIN 事件該次實例的起始時間,單位為 UTC 毫秒數。
END 事件該次實例的結束時間,單位為 UTC 毫秒數。
END_DAY 事件該次實例的結束日期,Julian 歷法,並與 Calendar 當前時區相關。
END_MINUTE 事件該次實例的結束時間,單位是自 Calendar 當前時區 0 點開始的分鍾數。
EVENT_ID 該次實例的事件 _ID
START_DAY 事件該次實例的開始日期,Julian 歷法,並與 Calendar 當前時區相關。
START_MINUTE 事件該次實例的開始時間,單位是自 Calendar 當前時區 0 點開始的分鍾數。

查詢 Instances 表

如果要查詢 Instances 表,需要在查詢 URI 中指定一個時間范圍。 在以下例子中,通過實現 CalendarContract.EventsColumns 接口, CalendarContract.Instances 讀取了 TITLE 字段。也就是說,通過數據庫映射層返回了 TITLE ,而不是通過查詢底層數據表 CalendarContract.Instances

private static final String DEBUG_TAG = "MyActivity";
public static final String[] INSTANCE_PROJECTION = new String[] {
    Instances.EVENT_ID,      // 0
    Instances.BEGIN,         // 1
    Instances.TITLE          // 2
  };
  
// 為上面的映射數組定義索引常量
private static final int PROJECTION_ID_INDEX = 0;
private static final int PROJECTION_BEGIN_INDEX = 1;
private static final int PROJECTION_TITLE_INDEX = 2;
...

// 定義要查詢的事件實例的日期范圍
Calendar beginTime = Calendar.getInstance();
beginTime.set(2011, 9, 23, 8, 0);
long startMillis = beginTime.getTimeInMillis();
Calendar endTime = Calendar.getInstance();
endTime.set(2011, 10, 24, 8, 0);
long endMillis = endTime.getTimeInMillis();
  
Cursor cur = null;
ContentResolver cr = getContentResolver();

// 要在 Instances 表中查詢的事件 ID 
String selection = Instances.EVENT_ID + " = ?";
String[] selectionArgs = new String[] {"207"};

// 根據日期范圍構造查詢
Uri.Builder builder = Instances.CONTENT_URI.buildUpon();
ContentUris.appendId(builder, startMillis);
ContentUris.appendId(builder, endMillis);

// 提交查詢
cur =  cr.query(builder.build(), 
    INSTANCE_PROJECTION, 
    selection, 
    selectionArgs, 
    null);
   
while (cur.moveToNext()) {
    String title = null;
    long eventID = 0;
    long beginVal = 0;    
    
    // 讀取各字段的值
    eventID = cur.getLong(PROJECTION_ID_INDEX);
    beginVal = cur.getLong(PROJECTION_BEGIN_INDEX);
    title = cur.getString(PROJECTION_TITLE_INDEX);
              
    // 利用這些數據完成一些操作
    Log.i(DEBUG_TAG, "Event:  " + title); 
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(beginVal);  
    DateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");
    Log.i(DEBUG_TAG, "Date: " + formatter.format(calendar.getTime()));    
    }
 }

日程相關的 Intent

讀寫日程數據時,應用程序並不需要申請權限。 也可以利用 Android 內置 Calendar 應用的 Intent 來完成讀寫操作。 下表列出了 Calendar Provider 支持的 Intent:

Action URI 說明 附加數據
VIEW

content://com.android.calendar/time/<ms_since_epoch>

也可以用 CalendarContract.CONTENT_URI 來引用該 URI。關於該 Intent 的使用實例,請參閱 使用 Intent 查看日程數據
打開日歷,時間由<ms_since_epoch>指定。
VIEW

content://com.android.calendar/events/<event_id>

也可以用 Events.CONTENT_URI 來引用該 URI。關於該 Intent 的使用實例,請參閱 使用 Intent 查看日程數據
查看 <event_id> 指定的事件。 CalendarContract.EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_END_TIME
EDIT content://com.android.calendar/events/<event_id> 也可以用 Events.CONTENT_URI. 來引用該 URI。關於該 Intent 的使用實例,請參閱 使用 Intent 編輯日程數據 編輯 <event_id> 指定的事件。 CalendarContract.EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_END_TIME
EDIT INSERT

content://com.android.calendar/events

也可以用 Events.CONTENT_URI 來引用該 URI。關於該 Intent 的使用實例,請參閱 使用 Intent 插入日程數據.
創建事件。 本表后面列出的任何附加數據。

下表列出了 Calendar Provider 支持的 Intent 附加數據:

Intent Extra 說明
Events.TITLE 事件名稱。
CalendarContract.EXTRA_EVENT_BEGIN_TIME 事件的起始時間,單位是1970年1月1日以來的毫秒數。
CalendarContract.EXTRA_EVENT_END_TIME 事件的結束時間,單位是1970年1月1日以來的毫秒數。
CalendarContract.EXTRA_EVENT_ALL_DAY 布爾值,標明事件是否占用一整天。值為truefalse
Events.EVENT_LOCATION 事件所在地區。
Events.DESCRIPTION 事件描述信息。
Intent.EXTRA_EMAIL 被邀請參加人員的 Email 地址,中間以逗號分隔。
Events.RRULE 事件重復執行的規則。
Events.ACCESS_LEVEL 事件是私有的還是公開的。
Events.AVAILABILITY 事件是在忙時計時,還是空閑時計時。

下一節將介紹這些 Intent 的使用。

利用 Intent 插入事件

利用 INSERT Intent ,應用程序可以將事件插入工作交給 Calendar 來完成。 這樣,就不需要在Manifest 文件中包含 WRITE_CALENDAR 權限。

當用戶運行這類應用程序時,應用將會向 Calendar 發送 Intent 來完成事件添加操作。 INSERT Intent 利用其附加數據將事件信息填充到 Calendar 的表單中。 然后,用戶可以根據需要取消事件、編輯表單數據,或者把事件保存到日歷中。

下面給出了一段代碼,在2012年1月1日安排一個事件,時間是上午7:30到8:30。 請留意代碼中的以下內容:

Calendar beginTime = Calendar.getInstance();
beginTime.set(2012, 0, 19, 7, 30);
Calendar endTime = Calendar.getInstance();
endTime.set(2012, 0, 19, 8, 30);
Intent intent = new Intent(Intent.ACTION_INSERT)
        .setData(Events.CONTENT_URI)
        .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis())
        .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis())
        .putExtra(Events.TITLE, "Yoga")
        .putExtra(Events.DESCRIPTION, "Group class")
        .putExtra(Events.EVENT_LOCATION, "The gym")
        .putExtra(Events.AVAILABILITY, Events.AVAILABILITY_BUSY)
        .putExtra(Intent.EXTRA_EMAIL, "rowan@example.com,trevor@example.com");
startActivity(intent);

利用 Intent 編輯事件

正如 修改事件 一節所述,事件可以直接進行更新。但利用 EDIT Intent ,可以讓不具備權限的應用將事件編輯工作交給 Calendar 應用來完成。 用戶在 Calendar 中完成事件編輯之后,可以返回調用方應用。

下面的例子通過 Intent 設置某個事件的標題,並且用戶可以在 Calendar 中編輯該事件。

long eventID = 208;
Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
Intent intent = new Intent(Intent.ACTION_EDIT)
    .setData(uri)
    .putExtra(Events.TITLE, "My New Title");
startActivity(intent);

利用 Intent 查看日程數據

Calender Provider 提供了兩種方式來使用 VIEW Intent:

  • 以指定日期打開 Calendar 應用
  • 查看事件

下面的例子演示了以指定日期打開 Calendar 的方式:

// 日期和時間以1970年1月1日以來的毫秒數給出
long startMillis;
...
Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon();
builder.appendPath("time");
ContentUris.appendId(builder, startMillis);
Intent intent = new Intent(Intent.ACTION_VIEW)
    .setData(builder.build());
startActivity(intent);

以下是查看某個事件的例子:

long eventID = 208;
...
Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
Intent intent = new Intent(Intent.ACTION_VIEW)
   .setData(uri);
startActivity(intent);

Sync Adapter

應用程序和 Sync Adapter 在訪問 Calendar Provider 時存在些許微小的差別:

  • Sync Adapter 需要聲明其為 Sync Adapter 身份,把 CALLER_IS_SYNCADAPTER 設為 true 即可。
  • Sync Adapter 需要以 URI 參數的方式指定 ACCOUNT_NAMEACCOUNT_TYPE
  • Sync Adapter 有權限訪問的字段比應用程序或 Widget 都要多一些。 例如,應用程序只能修改日程數據的一些表面性的屬性,諸如名稱、顯示名稱、是否可見、是否需要同步等。 相比之下,Sync Adapter 不僅能訪問這些字段,還能訪問諸如日歷配色、時區、訪問級別、地區等其他很多字段。 當然, Sync Adapter 訪問 ACCOUNT_NAMEACCOUNT_TYPE 是受限的。

下面是 Sync Adapter 可用於返回 URI 的助手方法:

static Uri asSyncAdapter(Uri uri, String account, String accountType) {
    return uri.buildUpon()
        .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,"true")
        .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
        .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
}

關於 Sync Adapter 的實例(與 Calendar 無關),請參閱 SampleSyncAdapter


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM