Xamarin.Android-Kalender

Kalender-API

Eine neue Gruppe von Kalender-APIs, die in Android 4 eingeführt wurden, unterstützt Anwendungen, die zum Lesen oder Schreiben von Daten in den Kalenderanbieter konzipiert sind. Diese APIs unterstützen eine Vielzahl von Interaktionsoptionen mit Kalenderdaten, einschließlich der Möglichkeit zum Lesen und Schreiben von Ereignissen, Teilnehmern und Erinnerungen. Wenn Sie den Kalenderanbieter in Ihrer Anwendung verwenden, werden daten, die Sie über die API hinzufügen, in der integrierten Kalender-App angezeigt, die im Lieferumfang von Android 4 enthalten ist.

Hinzufügen von Berechtigungen

Beim Arbeiten mit den neuen Kalender-APIs in Ihrer Anwendung müssen Sie zunächst die entsprechenden Berechtigungen zum Android-Manifest hinzufügen. Die Berechtigungen, die Sie hinzufügen müssen, sind android.permisson.READ_CALENDAR und android.permission.WRITE_CALENDAR, je nachdem, ob Sie Kalenderdaten lesen und/oder schreiben.

Verwenden des Kalendervertrags

Nachdem Sie die Berechtigungen festgelegt haben, können Sie mithilfe der CalendarContract Klasse mit Kalenderdaten interagieren. Diese Klasse stellt ein Datenmodell bereit, das Anwendungen verwenden können, wenn sie mit dem Kalenderanbieter interagieren. Die CalendarContract Anwendungen können die URIs in Kalenderentitäten auflösen, z. B. Kalender und Ereignisse. Außerdem bietet es eine Möglichkeit, mit verschiedenen Feldern in jeder Entität zu interagieren, z. B. den Namen und die ID eines Kalenders oder das Start- und Enddatum eines Ereignisses.

Sehen wir uns ein Beispiel an, das die Kalender-API verwendet. In diesem Beispiel untersuchen wir, wie Kalender und deren Ereignisse aufgezählt werden, und wie sie einem Kalender ein neues Ereignis hinzufügen.

Auflisten von Kalendern

Zunächst untersuchen wir, wie Sie die Kalender aufzählen, die in der Kalender-App registriert wurden. Dazu können wir eine Instanziierung durchführen CursorLoader. In Android 3.0 (API 11) eingeführt, CursorLoader ist die bevorzugte Methode zum Nutzen eines ContentProvider. Mindestens müssen wir den Inhalts-URI für Kalender und die Spalten angeben, die zurückgegeben werden sollen. Diese Spaltenspezifikation wird als Projektion bezeichnet.

Durch Aufrufen der CursorLoader.LoadInBackground Methode können wir einen Inhaltsanbieter für Daten abfragen, z. B. den Kalenderanbieter. LoadInBackground führt den tatsächlichen Ladevorgang aus und gibt eine Cursor mit den Ergebnissen der Abfrage zurück.

Dies CalendarContract hilft uns dabei, sowohl den Inhalt Uri als auch die Projektion anzugeben. Um den Inhalt Uri für die Abfrage von Kalendern abzurufen, können wir einfach die CalendarContract.Calendars.ContentUri Eigenschaft wie folgt verwenden:

var calendarsUri = CalendarContract.Calendars.ContentUri;

Die Verwendung der CalendarContract gewünschten Kalenderspalten ist ebenso einfach. Wir fügen nur Felder in der CalendarContract.Calendars.InterfaceConsts Klasse zu einem Array hinzu. Der folgende Code enthält beispielsweise die ID des Kalenders, den Anzeigenamen und den Kontonamen:

string[] calendarsProjection = {
    CalendarContract.Calendars.InterfaceConsts.Id,
    CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName,
    CalendarContract.Calendars.InterfaceConsts.AccountName
};

Dies Id ist wichtig, wenn Sie eine SimpleCursorAdapter Bindung der Daten an die Benutzeroberfläche verwenden, da wir in Kürze sehen werden. Wenn der Inhalts-URI und die Projektion vorhanden sind, instanziieren CursorLoader und rufen wir die CursorLoader.LoadInBackground Methode auf, um einen Cursor mit den Kalenderdaten wie unten dargestellt zurückzugeben:

var loader = new CursorLoader(this, calendarsUri, calendarsProjection, null, null, null);
var cursor = (ICursor)loader.LoadInBackground();

Die Benutzeroberfläche für dieses Beispiel enthält ein ListView, mit jedem Element in der Liste, das einen einzelnen Kalender darstellt. Der folgende XML-Code zeigt das Markup, das folgendes ListViewenthält:

<?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>

Außerdem müssen wir die Benutzeroberfläche für jedes Listenelement angeben, das in einer separaten XML-Datei wie folgt platziert wird:

<?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>

Ab diesem Zeitpunkt ist es einfach normaler Android-Code, die Daten vom Cursor an die Benutzeroberfläche zu binden. Wir verwenden folgendes 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;

Im obigen Code übernimmt der Adapter die im sourceColumns Array angegebenen Spalten und schreibt sie in die Benutzeroberflächenelemente im targetResources Array für jeden Kalendereintrag im Cursor. Die hier verwendete Aktivität ist eine Unterklasse von ListActivity; sie enthält die ListAdapter Eigenschaft, auf die wir den Adapter festlegen.

Hier ist ein Screenshot mit dem Endergebnis, in dem die Kalenderinformationen im ListViewFolgenden angezeigt werden:

CalendarDemo wird im Emulator ausgeführt und zeigt zwei Kalendereinträge an.

Auflisten von Kalenderereignissen

Als Nächstes sehen wir uns an, wie sie die Ereignisse für einen bestimmten Kalender aufzählen. Auf dem obigen Beispiel wird eine Liste von Ereignissen angezeigt, wenn der Benutzer einen der Kalender auswählt. Daher müssen wir die Elementauswahl im vorherigen Code behandeln:

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

In diesem Code erstellen wir eine Absicht, um eine Aktivität vom Typ EventListActivity"Aktivität" zu öffnen, wobei die KALENDER-ID in der Absicht übergeben wird. Wir benötigen die ID, um zu wissen, welcher Kalender nach Ereignissen gesucht werden soll. In der EventListActivityMethode "s OnCreate " können wir die ID wie unten gezeigt abrufen Intent :

_calId = Intent.GetIntExtra ("calId", -1);

Jetzt fragen wir Ereignisse für diese Kalender-ID ab. Der Vorgang zum Abfragen von Ereignissen ähnelt der Art, wie wir zuvor für eine Liste von Kalendern abgefragt haben, nur diesmal arbeiten wir mit der CalendarContract.Events Klasse. Der folgende Code erstellt eine Abfrage zum Abrufen von Ereignissen:

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

In diesem Code rufen wir zuerst den Inhalt Uri für Ereignisse aus der CalendarContract.Events.ContentUri Eigenschaft ab. Anschließend geben wir die Ereignisspalten an, die wir im eventsProjection-Array abrufen möchten. Schließlich instanziieren wir eine CursorLoader mit diesen Informationen und rufen die Methode des Ladeprogramms LoadInBackground auf, um eine Cursor mit den Ereignisdaten zurückzugeben.

Um die Ereignisdaten auf der Benutzeroberfläche anzuzeigen, können wir Markup und Code wie zuvor verwenden, um die Liste der Kalender anzuzeigen. Auch hier werden SimpleCursorAdapter die Daten wie im folgenden Code dargestellt an eine ListView Bindung gebunden:

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;

Der Standard Unterschied zwischen diesem Code und dem Code, den wir zuvor zum Anzeigen der Kalenderliste verwendet haben, ist die Verwendung einer ViewBinder, die in der Zeile festgelegt ist:

adapter.ViewBinder = new ViewBinder ();

Die ViewBinder Klasse ermöglicht es uns, die Bindung von Werten an Ansichten weiter zu steuern. In diesem Fall verwenden wir es, um die Startzeit des Ereignisses von Millisekunden in eine Datumszeichenfolge zu konvertieren, wie in der folgenden Implementierung gezeigt:

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

Dadurch wird eine Liste der Ereignisse angezeigt, wie unten dargestellt:

Screenshot der Beispiel-App mit drei Kalenderereignissen

Hinzufügen eines Kalenderereignisses

Wir haben gesehen, wie Kalenderdaten gelesen werden. Sehen wir uns nun an, wie Sie einem Kalender ein Ereignis hinzufügen. Damit dies funktioniert, müssen Sie unbedingt die Berechtigung einschließen, die android.permission.WRITE_CALENDAR wir zuvor Erwähnung. Um einem Kalender ein Ereignis hinzuzufügen, gehen wir wie folgt vor:

  1. Erstellen Sie eine ContentValues-Instanz.
  2. Verwenden Sie Schlüssel aus der CalendarContract.Events.InterfaceConsts Klasse, um die ContentValues Instanz aufzufüllen.
  3. Legen Sie die Zeitzonen für die Start- und Endzeiten des Ereignisses fest.
  4. Verwenden Sie eine ContentResolver , um die Ereignisdaten in den Kalender einzufügen.

Der folgende Code veranschaulicht die folgenden Schritte:

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

Beachten Sie, dass eine Ausnahme Java.Lang.IllegalArgumentException ausgelöst wird, wenn die Zeitzone nicht festgelegt wird. Da Ereigniszeitwerte seit der Epoche in Millisekunden ausgedrückt werden müssen, erstellen wir eine GetDateTimeMS Methode (in EventListActivity) zum Konvertieren unserer Datumsspezifikationen in Millisekundenformat:

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

Wenn wir der Benutzeroberfläche der Ereignisliste eine Schaltfläche hinzufügen und den obigen Code im Klickereignishandler der Schaltfläche ausführen, wird das Ereignis dem Kalender hinzugefügt und in unserer Liste aktualisiert, wie unten dargestellt:

Screenshot der Beispiel-App mit Kalenderereignissen gefolgt von der Schaltfläche

Wenn wir die Kalender-App öffnen, sehen wir, dass das Ereignis auch dort geschrieben wird:

Screenshot der Kalender-App mit dem ausgewählten Kalenderereignis

Wie Sie sehen können, ermöglicht Android leistungsstarken und einfachen Zugriff auf das Abrufen und Speichern von Kalenderdaten, sodass Anwendungen Kalenderfunktionen nahtlos integrieren können.