Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android官方文檔之Calendar Provider

Android官方文檔之Calendar Provider

編輯:關於Android編程

Calendar Provider是一個用於提供用戶標記在日歷上事件的數據倉庫。Calendar Provider 的API提供了包括增刪改查在內的一系列操作日歷事件的方法。

您可以在自己的應用程序或Adapter中使用Calendar Provider 的API。Adapter的相關用法將在本文的最後介紹。


通常來說,要訪問日歷應用程序中的數據,需要您在manifest中聲明權限;為了簡化操作, Calendar Provider 提供了一系列的Intents,使用這些Intents可以方便添加、查看、編輯 日歷應用程序中的事件(take users to the Calendar application to insert, view, and edit events),這樣一來,您可以與日歷應用程序交互以獲取日歷應用的數據信息,而且不需要您聲明權限,也不需要自己建立日歷事件的視圖。


本文將介紹Calendar Provider的相關內容,如需訪問官方原文,您可以點擊這個鏈接:《Calendar Provider》。


基礎概要(Basics)


Content providers存儲了數據,並提供了API以便應用程序可以訪問Content providers管理的數據。Content providers管理的數據通常是關系型數據庫中的一系列表結構,表中的每一行表示一條記錄(record),每一列表示該記錄的一個特定屬性。通過Calendar Provider API,您可以方便地讀寫日歷應用程序中由Calendar Provider管理的一系列表中的記錄。


每一個content provider都向外界暴露了一個獨一無二的Uri地址,通過這個地址,您可以訪問到這個content provider,以讀寫它所管轄的數據。所有的Uri都以content://開頭。為了能訪問到Calendar Provider中表的數據,應當采用 .CONTENT_URI 的Uri格式,其中class就表示表名,如Events.CONTENT_URI


下圖展示了Calendar Provider管轄的數據模型,該模型由一個叫做Events的表作為主表,通過該表可以鏈接至其他表:
這裡寫圖片描述


CalendarContract類中定義了Calendar Provider中各種表所對應的模型,並存儲相關信息,如下表所示:


表名(模型名) Tables(class) 描述(Description) CalendarContract.Calendars 該表中包含了具體的日歷信息(calendar-specific information),每一行表示一個日期中的具體內容,如名字,顏色,同步信息 等 CalendarContract.Events 該表中包含了具體的事件信息(event-specific information),每一行表示一個獨立的事件,如,事件標題、發生地點、起始時間、結束時間 等(event title, location, start time, end time, and so on)。可以將事件設置為一次性事件或重復事件,而參加者(Attendees)、提醒信息(reminders)、其他屬性信息(extended properties)都被存儲於相應的表中,這些表中都各自包含一個EVENT_ID 字段,作為Events表的外鍵(一對多:一個事件可以有多個提醒信息 等。但一個提醒信息只能針對一個事件) CalendarContract.Instances 該表記錄了事件的起始和結束時間。每一行表示一個事件的發生情況。對於一次性事件,該表和Events表是一對一關系(一對一:一個事件只有一對起訖時間,而一對起訖時間也只對應一個事件) ;對於重復事件,該表和Events表是多對多關系(多對多:一個事件可以有多對起訖時間,而一對起訖時間也可以應用於多個事件) CalendarContract.Attendees 該表記錄了事件的參加者信息(holds the event attendee (guest) information),每一行表示了一個事件中的一個參加者信息。 CalendarContract.Reminders 該表記錄了警告和通知信息(alert/notification data),每一行表示一個事件的警告,一個事件可以有多個警告,但有最大警告數的限制,用MAX_REMINDERS 指定。提醒信息會在設定提醒時間之前的若干分鐘進行預提醒,以通知用戶做好准備

使用Calendar Provider API需要注意的事:

插入、更新、查看日歷事件(Inserting, updating, and viewing calendar events):為了讀寫Calendar Provider中的數據,需要您添加讀寫權限。若您並不打算開發一款功能齊全的日歷應用程序或者同步adapter,那麼您無需申請權限(, if you’re not building a full-fledged calendar application or sync adapter, requesting these permissions isn’t necessary),您可以使用Intents訪問系統自帶的日歷應用程序,並返回結果。有關Calendar Intents的內容,我將在後續翻譯。

同步adapter(Sync adapters):同步adapter可以從用戶的設備中同步日歷數據(A sync adapter synchronizes the calendar data on a user’s device with another server or data source)。CalendarContract.CalendarsCalendarContract.Events表中都提供了同步adapter的字段。Calendar Provider和其他應用程序不可修改這個字段中的內容。事實上,這對於外部應用是隱藏的。


用戶權限(User Permissions)


為了查詢Calendar Provider中的數據,您應在manifest文件中添加READ_CALENDAR權限,為了增、刪、改 Calendar Provider中的數據,您應在manifest文件中添加WRITE_CALENDAR權限,如下所示:



    
    
    
    ...

日歷表(Calendars Table)


CalendarContract.Calendars表中包含了日歷的詳細信息。下面介紹了表中的字段信息。

字段(Constant) 描述(Description) NAME 日歷的名字 CALENDAR_DISPLAY_NAME 向用戶展示的日歷名字(The name of this calendar that is displayed to the user) VISIBLE boolean類型,用於決定是否將日歷展示給用戶。若值為0表示與該日歷綁定的事件不予顯示。值為1則相反。該值直接影響了CalendarContract.Instances表中的內容 SYNC_EVENTS boolean類型,表示是否同步設備中的日歷數據。

查詢日歷表(Querying a calendar)


下面演示了查詢的示例,需要注意的是,您需要在異步線程中執行查詢操作:


// 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[] {"[email protected]", "com.google",
        "[email protected]"}; 
// 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...

   ...
}

修改日歷表(Modifying a calendar)


修改日歷表實際上是修改表中的某一行或若干行數據,您可以直接在Uri中追加需要修改的行(調用withAppendedId()),或使用selection 篩選行,selection 應為_id=?形式,而selectionArg 是calendar表的_ID,示例如下:

private static final String DEBUG_TAG = "MyActivity";
...
long calID = 2;
ContentValues values = new ContentValues();
// The new display name for the calendar
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);

事件表(Events Table)


CalendarContract.Events表記錄了事件的具體信息,為了操作該表,您同樣需要添加相應權限。

下面是Events 表中的字段信息:

字段(Constant) 描述(Description) CALENDAR_ID Calender表的外鍵 ORGANIZER 事件的Email TITLE 事件的標題 EVENT_LOCATION 事件的發生地點 DESCRIPTION 事件描述 DTSTART 事件起始時間 DTEND 事件結束時間 EVENT_TIMEZONE 事件發生的時區 EVENT_END_TIMEZONE 結束時間的時區 DURATION 事件持續時間,使用RFC5545 格式,如PT1H表示事件將持續一小時,P2W表示事件將持續兩周 ALL_DAY boolean類型,表示是否為全天候事件,0表示“是全天候事件”,1表示“不是全天候事件” RRULE 循環觸發事件的條件,如:FREQ=WEEKLY;COUNT=10;WKST=SU,您可以參考這個例子 RDATE 事件循環的時間,您可以與RRULE一並使用 AVAILABILITY 將此事件視為忙碌時間還是可調度的空閒時間 GUESTS_CAN_MODIFY 來賓是否可修改事件 GUESTS_CAN_INVITE_OTHERS 是否可以邀請其他來賓 GUESTS_CAN_SEE_GUESTS 來賓是否可查看參加者列表

添加事件(Adding Events)


當您打算插入一條新的事件時,推薦使用INSERT Intent,當然您也可以直接插入事件,需要注意的事項如下:

必須包含CALENDAR_IDDTSTART字段;

必須包含EVENT_TIMEZONE字段,調用getAvailableIDs()方法獲取時區的ID。如使用Intent插入事件,則系統會自動包含時區信息;

若是一次性事件,則必須包含DTEND字段;

對於一次性事件,應包含DURATION字段,而不應包含RRULE 或 RDATE字段,如使用Intent插入事件,則系統會自動包含事件的持續時間;


下面通過一個例子演示插入事件,您同樣需要把操作放在異步線程中執行:

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);

// get the event ID that is the last element in the Uri
long eventID = Long.parseLong(uri.getLastPathSegment());
// 
// ... do something with event ID
//
//

您可以通過返回的事件ID執行其他日歷操作,如在實踐中加入參加者或提醒(to add attendees or reminders to an event)。


修改事件(Updating Events)


推薦使用EDIT Intent修改事件,但也可以手動修改,示例如下:

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

刪除事件(Deleting Events)


示例如下:

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 Table)


CalendarContract.Attendees表的一行表示一個事件的參加者信息。調用query()方法將返回某個事件(表中的EVENT_ID字段為Event表的外鍵,該字段的值決定了參加者所屬的事件)的參加者列表。
下面介紹了參加者表的字段信息:

字段(Constant) 描述(Description) EVENT_ID Event表的外鍵 ATTENDEE_NAME 參加者的姓名 ATTENDEE_EMAIL 參加者的Email ATTENDEE_RELATIONSHIP 參加者的職責,下列值之一:RELATIONSHIP_ATTENDEERELATIONSHIP_NONERELATIONSHIP_ORGANIZERRELATIONSHIP_PERFORMERRELATIONSHIP_SPEAKER ATTENDEE_TYPE 參加者的重要程度,下列值之一:TYPE_REQUIREDTYPE_OPTIONAL ATTENDEE_STATUS 參加者的狀態,下列值之一:ATTENDEE_STATUS_ACCEPTEDATTENDEE_STATUS_DECLINEDATTENDEE_STATUS_INVITEDATTENDEE_STATUS_NONEATTENDEE_STATUS_TENTATIVE

添加參加者(Adding Attendees)


下面是一個添加參加者的示例,需要注意的是必須包含EVENT_ID字段:

long eventID = 202;
...
ContentResolver cr = getContentResolver();
ContentValues values = new ContentValues();
values.put(Attendees.ATTENDEE_NAME, "Trevor");
values.put(Attendees.ATTENDEE_EMAIL, "[email protected]");
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 Table)


CalendarContract.Reminders表中的一行表示了某個事件的提醒事項,下面介紹該表的字段信息:

字段(Constant) 描述(Description) EVENT_ID Event表的外鍵 MINUTES 事件發生前的分鐘數,應在達到該時間時發出提醒 METHOD 服務器上設置的提醒方法。下列值之一:METHOD_ALERTMETHOD_DEFAULTMETHOD_EMAILMETHOD_SMS

添加提醒事項(Adding Reminders)


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 Table)


CalendarContract.Instances表中的每一行記錄了一個事件的起訖時間,該表中的內容不可修改,只能查詢:

字段(Constant) 描述(Description) BEGIN 實例的開始時間,以協調世界時毫秒數表示 END 實例的結束時間,以協調世界時毫秒數表示 END_DAY 與日歷時區相應的實例儒略歷結束日(The Julian end day of the instance, relative to the Calendar’s time zone) END_MINUTE 從日歷時區午夜開始計算的實例結束時間(分鐘) EVENT_ID Event表的主鍵 START_DAY 與日歷時區相應的實例儒略歷開始日 START_MINUTE 從日歷時區午夜開始計算的實例開始時間(分鐘)

查詢實例表(Querying the Instances table)


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
  };

// The indices for the projection array above.
private static final int PROJECTION_ID_INDEX = 0;
private static final int PROJECTION_BEGIN_INDEX = 1;
private static final int PROJECTION_TITLE_INDEX = 2;
...

// Specify the date range you want to search for recurring
// event instances
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();

// The ID of the recurring event whose instances you are searching
// for in the Instances table
String selection = Instances.EVENT_ID + " = ?";
String[] selectionArgs = new String[] {"207"};

// Construct the query with the desired date range.
Uri.Builder builder = Instances.CONTENT_URI.buildUpon();
ContentUris.appendId(builder, startMillis);
ContentUris.appendId(builder, endMillis);

// Submit the query
cur =  cr.query(builder.build(), 
    INSTANCE_PROJECTION, 
    selection, 
    selectionArgs, 
    null);

while (cur.moveToNext()) {
    String title = null;
    long eventID = 0;
    long beginVal = 0;    

    // Get the field values
    eventID = cur.getLong(PROJECTION_ID_INDEX);
    beginVal = cur.getLong(PROJECTION_BEGIN_INDEX);
    title = cur.getString(PROJECTION_TITLE_INDEX);

    // Do something with the values. 
    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(Calendar Intents)


使用Calendar Intents,您無需添加權限,就能訪問Calendar Provider管理的表數據。
下面介紹了由Calendar Provider支持的Intent:

Action URI Description Extras VIEW content://com.android.calendar/time/ 打開日歷後定位到 指定的時間 無 VIEW content://com.android.calendar/events/ 查看 指定的事件 CalendarContract.EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_END_TIME EDIT content://com.android.calendar/events/ 編輯 指定的事件 CalendarContract.EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_END_TIME EDIT INSERT content://com.android.calendar/events 創建事件 下表列出的任一 Extra
Intent Extra Description Events.TITLE 事件的名字 CalendarContract.EXTRA_EVENT_BEGIN_TIME 事件開始時間,以從公元紀年開始計算的毫秒數表示 CalendarContract.EXTRA_EVENT_END_TIME 事件結束時間,以從公元紀年開始計算的毫秒數表示 CalendarContract.EXTRA_EVENT_ALL_DAY boolean類型,0表示全天候事件,1表示非全天候事件 Events.EVENT_LOCATION 事件的地點 Events.DESCRIPTION 事件描述 Intent.EXTRA_EMAIL 受邀者Email地址列表,以逗號分隔 Events.RRULE 事件的重復發生規則 Events.ACCESS_LEVEL 事件是私人性質還是公共性質 Events.AVAILABILITY 將此事件視為忙碌時間還是可調度的空閒時間

使用Intent添加事件(Using an intent to insert an event)


當您在自己的應用中使用Intent啟動日歷應用程序時,應用會轉到日歷來完成事件添加操作,可以將預填充日歷事件的詳細信息附加在INSERT Intent中的extra 字段裡,待程序切換至日歷應用後,這些信息會自動填充至相應的欄目中,用戶只需選擇保存、編輯、取消 等選項即可。

下面通過一段代碼演示了添加一條發生於2012年1月19日的待辦事件,該事件的起始時間為上午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, "[email protected],[email protected]");
startActivity(intent);

使用Intent編輯事件(Using an intent to edit an event)


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查看日歷信息(Using intents to view calendar data)


查看日歷信息,有兩種查看結果:

查詢指定日期的日歷信息;

查詢指定日期的事件。


查看指定日期的日歷信息如下:

// A date-time specified in milliseconds since the epoch.
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);

同步Adapters(Sync Adapters)


使用同步Adapters訪問Calendar Provider中數據的方式 與上述方式差別不大:

同步Adapter需要通過將 CALLER_IS_SYNCADAPTER 設置為 true 來表明它是同步適配器;

需提供 ACCOUNT_NAMEACCOUNT_TYPE 作為 URI 中的查詢參數;

與應用或小工具相比,同步適配器擁有寫入權限的列更多。 例如,應用只能修改日歷的少數幾種特性, 例如其名稱、顯示名稱、能見度設置以及是否同步日歷。 相比之下,同步適配器不僅可以訪問這些列,還能訪問許多其他列, 例如日歷顏色、時區、訪問級別、地點等等。不過,同步適配器受限於它指定的 ACCOUNT_NAMEACCOUNT_TYPE


同步Adapter的示例如下:

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();
 }
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved