Xamarin.Android 行事曆
行事曆 API
Android 4 中引進的新一組行事曆 API 支援設計來讀取或寫入行事曆提供者的應用程式。 這些 API 支援與行事曆數據的豐富互動選項,包括讀取和寫入事件、出席者和提醒的能力。 藉由在應用程式中使用行事曆提供者,您透過 API 新增的數據會出現在 Android 4 隨附的內建行事曆應用程式中。
新增許可權
在應用程式中使用新的行事曆 API 時,您需要做的第一件事就是將適當的許可權新增至 Android 指令清單。 您需要新增的許可權是 android.permisson.READ_CALENDAR
和 android.permission.WRITE_CALENDAR
,視您是要讀取和/或寫入行事曆數據而定。
使用行事曆合約
設定許可權之後,您可以使用 類別與行事曆資料 CalendarContract
互動。 這個類別提供數據模型,應用程式可以在與行事曆提供者互動時使用。 CalendarContract
可讓應用程式將 URI 解析為行事曆實體,例如行事曆和事件。 它也提供一種方式來與每個實體中的各種欄位互動,例如行事曆的名稱和標識碼,或事件的開始和結束日期。
讓我們看看使用行事曆 API 的範例。 在此範例中,我們將檢查如何列舉行事曆及其事件,以及如何將新事件新增至行事曆。
列出行事曆
首先,讓我們檢查如何列舉已在行事曆應用程式中註冊的行事曆。 若要這樣做,我們可以具現化 CursorLoader
。 在Android 3.0中引進(API 11), CursorLoader
是取用的 ContentProvider
慣用方式。 我們至少必須指定行事曆的內容 URI,以及我們想要傳回的數據行;此數據行規格稱為 投影。
CursorLoader.LoadInBackground
呼叫 方法可讓我們查詢內容提供者的數據,例如行事曆提供者。
LoadInBackground
會執行實際的載入作業,並傳回 Cursor
具有查詢結果的 。
可 CalendarContract
協助我們同時指定內容 Uri
和投影。 若要取得查詢行事曆的內容 Uri
,我們只需要使用 CalendarContract.Calendars.ContentUri
如下的 屬性:
var calendarsUri = CalendarContract.Calendars.ContentUri;
CalendarContract
使用 來指定我們想要的行事曆數據行同樣簡單。 我們只會將類別中的 CalendarContract.Calendars.InterfaceConsts
欄位新增至數位。 例如,下列程式代碼包含行事曆的識別碼、顯示名稱和帳戶名稱:
string[] calendarsProjection = {
CalendarContract.Calendars.InterfaceConsts.Id,
CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName,
CalendarContract.Calendars.InterfaceConsts.AccountName
};
Id
如果您使用 SimpleCursorAdapter
將數據系結至UI,請務必包含 ,因為我們很快就會看到。 在內容 URI 和投影就緒后,我們會具現化 CursorLoader
和呼叫 CursorLoader.LoadInBackground
方法,以傳回具有行事曆數據的數據指標,如下所示:
var loader = new CursorLoader(this, calendarsUri, calendarsProjection, null, null, null);
var cursor = (ICursor)loader.LoadInBackground();
此範例的 UI 包含 , ListView
清單中每個專案都代表單一行事曆。 下列 XML 顯示包含 的 ListView
標記:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView
android:id="@android:id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
此外,我們需要為每個清單專案指定UI,我們會將它放在個別的 XML 檔案中,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:id="@+id/calDisplayName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16dip" />
<TextView android:id="@+id/calAccountName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12dip" />
</LinearLayout>
從這一點開始,將數據指標中的數據系結至UI只是一般的Android程式碼。 我們將使用 SimpleCursorAdapter
,如下所示:
string[] sourceColumns = {
CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName,
CalendarContract.Calendars.InterfaceConsts.AccountName };
int[] targetResources = {
Resource.Id.calDisplayName, Resource.Id.calAccountName };
SimpleCursorAdapter adapter = new SimpleCursorAdapter (this,
Resource.Layout.CalListItem, cursor, sourceColumns, targetResources);
ListAdapter = adapter;
在上述程式代碼中,配接器會取得數位中指定的 sourceColumns
數據行,並將其寫入數據指標中每個行事歷專案之陣列中的 targetResources
使用者介面元素。 此處使用的 Activity 是 的 ListActivity
子類別;它包含 ListAdapter
我們設定配接器的 屬性。
以下是顯示結束結果的螢幕快照,其中顯示行事曆資訊:ListView
列出行事曆事件
接下來讓我們看看如何列舉指定行事曆的事件。 以上述範例為基礎,當用戶選取其中一個行事歷時,我們將呈現事件清單。 因此,我們必須處理上一個程式代碼中的項目選取:
ListView.ItemClick += (sender, e) => {
int i = (e as ItemEventArgs).Position;
cursor.MoveToPosition(i);
int calId =
cursor.GetInt (cursor.GetColumnIndex (calendarsProjection [0]));
var showEvents = new Intent(this, typeof(EventListActivity));
showEvents.PutExtra("calId", calId);
StartActivity(showEvents);
};
在此程式代碼中,我們會建立意圖來開啟 類型的 EventListActivity
活動,並在意圖中傳遞行事曆的標識碼。 我們需要標識符,才能知道要查詢事件的行事曆。 EventListActivity
在 的 方法中OnCreate
,我們可以從 Intent
擷取標識碼,如下所示:
_calId = Intent.GetIntExtra ("calId", -1);
現在讓我們查詢此行事曆標識碼的事件。 查詢事件的程式類似於我們稍早查詢行事曆清單的方式,但這次我們將使用 CalendarContract.Events
類別。 下列程式代碼會建立查詢以擷取事件:
var eventsUri = CalendarContract.Events.ContentUri;
string[] eventsProjection = {
CalendarContract.Events.InterfaceConsts.Id,
CalendarContract.Events.InterfaceConsts.Title,
CalendarContract.Events.InterfaceConsts.Dtstart
};
var loader = new CursorLoader(this, eventsUri, eventsProjection,
String.Format ("calendar_id={0}", _calId), null, "dtstart ASC");
var cursor = (ICursor)loader.LoadInBackground();
在此程式代碼中,我們會先從 CalendarContract.Events.ContentUri
屬性取得事件的內容Uri
。 然後,我們會指定我們想要在 eventsProjection 陣列中擷取的事件數據行。
最後,我們會使用這項資訊具現化 CursorLoader
,並呼叫載入器 LoadInBackground
的方法,以傳回 Cursor
事件資料的 。
若要在 UI 中顯示事件數據,我們可以使用標記和程式代碼,就像我們之前所做的一樣,來顯示行事曆清單。 同樣地,我們會使用 SimpleCursorAdapter
將數據系結至 , ListView
如下列程式代碼所示:
string[] sourceColumns = {
CalendarContract.Events.InterfaceConsts.Title,
CalendarContract.Events.InterfaceConsts.Dtstart };
int[] targetResources = {
Resource.Id.eventTitle,
Resource.Id.eventStartDate };
var adapter = new SimpleCursorAdapter (this, Resource.Layout.EventListItem,
cursor, sourceColumns, targetResources);
adapter.ViewBinder = new ViewBinder ();
ListAdapter = adapter;
此程式代碼和我們稍早用來顯示行事曆清單的程式代碼主要差異在於使用 ViewBinder
,其設定於行:
adapter.ViewBinder = new ViewBinder ();
類別 ViewBinder
可讓我們進一步控制如何將值系結至檢視。 在此情況下,我們會使用它將事件開始時間從毫秒轉換成日期字串,如下列實作所示:
class ViewBinder : Java.Lang.Object, SimpleCursorAdapter.IViewBinder
{
public bool SetViewValue (View view, Android.Database.ICursor cursor,
int columnIndex)
{
if (columnIndex == 2) {
long ms = cursor.GetLong (columnIndex);
DateTime date = new DateTime (1970, 1, 1, 0, 0, 0,
DateTimeKind.Utc).AddMilliseconds (ms).ToLocalTime ();
TextView textView = (TextView)view;
textView.Text = date.ToLongDateString ();
return true;
}
return false;
}
}
這會顯示事件清單,如下所示:
新增行事曆事件
我們已瞭解如何讀取行事曆數據。 現在讓我們看看如何將事件新增至行事曆。 若要讓這項功能運作,請務必包含 android.permission.WRITE_CALENDAR
我們稍早所述的許可權。 若要將事件新增至行事曆,我們將:
- 建立
ContentValues
執行個體。 - 使用類別中的
CalendarContract.Events.InterfaceConsts
索引鍵來填入ContentValues
實例。 - 設定事件開始和結束時間的時區。
ContentResolver
使用將事件資料插入行事曆中。
下列程式代碼說明下列步驟:
ContentValues eventValues = new ContentValues ();
eventValues.Put (CalendarContract.Events.InterfaceConsts.CalendarId,
_calId);
eventValues.Put (CalendarContract.Events.InterfaceConsts.Title,
"Test Event from M4A");
eventValues.Put (CalendarContract.Events.InterfaceConsts.Description,
"This is an event created from Xamarin.Android");
eventValues.Put (CalendarContract.Events.InterfaceConsts.Dtstart,
GetDateTimeMS (2011, 12, 15, 10, 0));
eventValues.Put (CalendarContract.Events.InterfaceConsts.Dtend,
GetDateTimeMS (2011, 12, 15, 11, 0));
eventValues.Put(CalendarContract.Events.InterfaceConsts.EventTimezone,
"UTC");
eventValues.Put(CalendarContract.Events.InterfaceConsts.EventEndTimezone,
"UTC");
var uri = ContentResolver.Insert (CalendarContract.Events.ContentUri,
eventValues);
請注意,如果我們未設定時區,則會擲回 類型的 Java.Lang.IllegalArgumentException
例外狀況。 因為事件時間值必須以毫秒表示,因為自 epoch 之後,我們會建立 GetDateTimeMS
方法 (in EventListActivity
) 將日期規格轉換成毫秒格式:
long GetDateTimeMS (int yr, int month, int day, int hr, int min)
{
Calendar c = Calendar.GetInstance (Java.Util.TimeZone.Default);
c.Set (Java.Util.CalendarField.DayOfMonth, 15);
c.Set (Java.Util.CalendarField.HourOfDay, hr);
c.Set (Java.Util.CalendarField.Minute, min);
c.Set (Java.Util.CalendarField.Month, Calendar.December);
c.Set (Java.Util.CalendarField.Year, 2011);
return c.TimeInMillis;
}
如果我們將按鈕新增至事件清單 UI,並在按鈕的 Click 事件處理程式中執行上述程式代碼,事件就會新增至行事曆,並在清單中更新,如下所示:
如果我們開啟行事曆應用程式,我們也會看到事件也會寫入該處:
如您所見,Android 可讓您強大且輕鬆地存取擷取和保存行事曆數據,讓應用程式能夠順暢地整合行事歷功能。