Calendar Provider – Übersicht

Der Kalenderanbieter ist ein Repository für die Kalendertermine eines Nutzers. Mit der Calendar Provider API können Sie Kalender, Termine, Teilnehmer, Erinnerungen usw. abfragen, einfügen, aktualisieren und löschen.

Die Kalenderanbieter-API kann von Anwendungen und Synchronisierungsadaptern verwendet werden. Die Regeln variieren je nach Art des Programms, das die Aufrufe ausführt. In diesem Dokument geht es hauptsächlich um die Verwendung der Calendar Provider API als Anwendung. Informationen zu den Unterschieden zwischen Synchronisatoren finden Sie unter Synchronisatoren.

Normalerweise muss das Manifest einer App die entsprechenden Berechtigungen enthalten, die unter Nutzerberechtigungen beschrieben sind, um Kalenderdaten lesen oder schreiben zu können. Der Kalenderanbieter bietet eine Reihe von Intents, um häufige Vorgänge zu vereinfachen, wie unter Kalender-Intents beschrieben. Über diese Intents werden Nutzer zur Kalenderanwendung weitergeleitet, um Termine einzugeben, anzusehen und zu bearbeiten. Der Nutzer interagiert mit der Kalenderanwendung und kehrt dann zur ursprünglichen Anwendung zurück. Ihre Anwendung muss daher keine Berechtigungen anfordern und auch keine Benutzeroberfläche zum Anzeigen oder Erstellen von Ereignissen bereitstellen.

Grundlegende Informationen

Inhaltsanbieter speichern Daten und stellen sie für Anwendungen zur Verfügung. Die auf der Android-Plattform angebotenen Contentanbieter (einschließlich des Kalenderanbieters) stellen Daten in der Regel als eine Reihe von Tabellen auf der Grundlage eines relationalen Datenbankmodells bereit, wobei jede Zeile ein Datensatz und jede Spalte Daten eines bestimmten Typs und einer bestimmten Bedeutung enthält. Über die Kalenderanbieter-API können Anwendungen und Synchronadapter Lese-/Schreibzugriff auf die Datenbanktabellen erhalten, die die Kalenderdaten eines Nutzers enthalten.

Jeder Inhaltsanbieter stellt einen öffentlichen URI bereit (als Uri-Objekt verpackt), der seinen Datensatz eindeutig identifiziert. Ein Contentanbieter, der mehrere Datensätze (mehrere Tabellen) verwaltet, stellt für jeden einen separaten URI bereit. Alle URIs für Anbieter beginnen mit dem String „content://“. Damit wird angegeben, dass die Daten von einem Contentanbieter verwaltet werden. Der Calendar Provider definiert Konstanten für die URIs für jede seiner Klassen (Tabellen). Diese URIs haben das Format <class>.CONTENT_URI. Beispiel: Events.CONTENT_URI.

Abbildung 1 zeigt eine grafische Darstellung des Datenmodells des Kalenderanbieters. Es werden die Haupttabellen und die Felder angezeigt, die sie miteinander verknüpfen.

Datenmodell des Kalenderanbieters

Abbildung 1. Datenmodell des Kalenderanbieters

Ein Nutzer kann mehrere Kalender haben und verschiedene Kalender können mit verschiedenen Kontotypen verknüpft sein (z. B. Google Kalender, Exchange usw.).

Mit CalendarContract wird das Datenmodell von kalender- und terminbezogenen Informationen definiert. Diese Daten werden in einer Reihe von Tabellen gespeichert, die unten aufgeführt sind.

Table (Class) Beschreibung

CalendarContract.Calendars

Diese Tabelle enthält die kalenderspezifischen Informationen. Jede Zeile in dieser Tabelle enthält die Details für einen einzelnen Kalender, z. B. den Namen, die Farbe und die Synchronisierungsinformationen.
CalendarContract.Events Diese Tabelle enthält die ereignisspezifischen Informationen. Jede Zeile in dieser Tabelle enthält die Informationen zu einem einzelnen Ereignis, z. B. den Titel, den Ort, die Start- und Endzeit usw. Das Ereignis kann einmalig oder mehrmals stattfinden. Teilnehmer, Erinnerungen und erweiterte Properties werden in separaten Tabellen gespeichert. Sie haben jeweils ein EVENT_ID, das auf das _ID in der Ereignistabelle verweist.
CalendarContract.Instances Diese Tabelle enthält die Start- und Endzeit für jedes Auftreten eines Ereignisses. Jede Zeile in dieser Tabelle steht für ein einzelnes Ereignis. Für einmalige Ereignisse gibt es eine 1:1-Zuordnung von Instanzen zu Ereignissen. Für wiederkehrende Termine werden automatisch mehrere Zeilen generiert, die mehreren Vorkommen des Termins entsprechen.
CalendarContract.Attendees Diese Tabelle enthält die Informationen zu den Veranstaltungsteilnehmern (Gast). Jede Zeile steht für einen einzelnen Gast einer Veranstaltung. Hier werden die Art des Gastes und die Antwort des Gastes auf die Einladung zur Veranstaltung angegeben.
CalendarContract.Reminders Diese Tabelle enthält die Daten zu Benachrichtigungen. Jede Zeile steht für eine einzelne Benachrichtigung für ein Ereignis. Ein Ereignis kann mehrere Erinnerungen haben. Die maximale Anzahl von Erinnerungen pro Termin wird in MAX_REMINDERS angegeben und durch den Synchronisierungsadapter festgelegt, der Inhaber des jeweiligen Kalenders ist. Erinnerungen werden in Minuten vor dem Ereignis angegeben und haben eine Methode, die bestimmt, wie der Nutzer benachrichtigt wird.

Die Calendar Provider API ist flexibel und leistungsfähig. Gleichzeitig ist es wichtig, eine gute Nutzererfahrung zu bieten und die Integrität des Kalenders und seiner Daten zu schützen. Beachten Sie daher bei der Verwendung der API Folgendes:

  • Kalendertermine einfügen, aktualisieren und ansehen Wenn Sie Termine direkt im Kalenderanbieter einfügen, ändern und lesen möchten, benötigen Sie die entsprechenden Berechtigungen. Wenn Sie jedoch keine vollwertige Kalenderanwendung oder keinen Synchronadapter entwickeln, ist es nicht erforderlich, diese Berechtigungen anzufordern. Sie können stattdessen Intents verwenden, die von der Kalender-App von Android unterstützt werden, um Lese- und Schreibvorgänge an diese App weiterzuleiten. Wenn Sie die Intents verwenden, werden Nutzer von Ihrer App an die Kalender-App weitergeleitet, um den gewünschten Vorgang in einem vorausgefüllten Formular auszuführen. Danach werden sie zu Ihrer Anwendung zurückgeleitet. Wenn Sie Ihre Anwendung so entwerfen, dass sie gängige Vorgänge über Google Kalender ausführt, bieten Sie Ihren Nutzern eine einheitliche, robuste Benutzeroberfläche. Dies ist der empfohlene Ansatz. Weitere Informationen finden Sie unter Kalender-Intents.
  • Synchronisieren Sie die Adapter. Ein Synchronisierungsadapter synchronisiert die Kalenderdaten auf dem Gerät eines Nutzers mit einem anderen Server oder einer anderen Datenquelle. Die Tabellen CalendarContract.Calendars und CalendarContract.Events enthalten Spalten, die für die zu verwendenden Synchronisierungsadapter reserviert sind. Anbieter und Anwendungen dürfen sie nicht ändern. Sie sind nur dann sichtbar, wenn auf sie als Synchronadapter zugegriffen wird. Weitere Informationen zu Synchronisatoren finden Sie unter Synchronisatoren.

Nutzerberechtigungen

Zum Lesen von Kalenderdaten muss eine App die Berechtigung READ_CALENDAR in die Manifestdatei aufnehmen. Sie muss die Berechtigung WRITE_CALENDAR zum Löschen, Einfügen oder Aktualisieren von Kalenderdaten enthalten:

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

Tabelle „Kalender“

Die Tabelle CalendarContract.Calendars enthält Details für einzelne Kalender. Die folgenden Kalenderspalten können sowohl von einer Anwendung als auch von einem Synchronisierungsadapter geschrieben werden. Eine vollständige Liste der unterstützten Felder finden Sie in der CalendarContract.Calendars-Referenz.

Konstante Beschreibung
NAME Der Name des Kalenders.
CALENDAR_DISPLAY_NAME Der Name dieses Kalenders, der dem Nutzer angezeigt wird.
VISIBLE Ein boolescher Wert, der angibt, ob der Kalender angezeigt werden soll. Ein Wert von 0 gibt an, dass Termine, die mit diesem Kalender verknüpft sind, nicht angezeigt werden sollen. Ein Wert von 1 gibt an, dass Termine, die mit diesem Kalender verknüpft sind, angezeigt werden sollen. Dieser Wert wirkt sich auf die Generierung von Zeilen in der Tabelle CalendarContract.Instances aus.
SYNC_EVENTS Ein boolescher Wert, der angibt, ob der Kalender synchronisiert und seine Termine auf dem Gerät gespeichert werden sollen. Bei einem Wert von 0 wird festgelegt, dass dieser Kalender nicht synchronisiert und keine Termine auf dem Gerät gespeichert werden sollen. Der Wert „1“ besagt, dass Termine für diesen Kalender synchronisiert und die Termine auf dem Gerät gespeichert werden.

Kontotyp für alle Vorgänge angeben

Wenn Sie eine Abfrage für eine Calendars.ACCOUNT_NAME stellen, muss Calendars.ACCOUNT_TYPE auch in der Auswahl enthalten sein. Das liegt daran, dass ein bestimmtes Konto nur dann als eindeutig betrachtet wird, wenn sowohl sein ACCOUNT_NAME als auch sein ACCOUNT_TYPE eindeutig sind. ACCOUNT_TYPE ist der String, der dem Konto-Authenticator entspricht, der verwendet wurde, als das Konto mit der AccountManager registriert wurde. Es gibt auch einen speziellen Kontotyp namens ACCOUNT_TYPE_LOCAL für Kalender, die nicht mit einem Gerätekonto verknüpft sind. ACCOUNT_TYPE_LOCAL-Konten werden nicht synchronisiert.

Kalender abfragen

Das folgende Beispiel zeigt, wie Sie die Kalender eines bestimmten Nutzers abrufen. Der Abfragevorgang wird in diesem Beispiel der Einfachheit halber im Benutzeroberflächen-Thread („Hauptthread“) dargestellt. In der Praxis sollte dies in einem asynchronen Thread statt im Hauptthread erfolgen. Weitere Informationen finden Sie unter Ladeprogramme. Wenn Sie Daten nicht nur lesen, sondern auch ändern, lesen Sie den Hilfeartikel AsyncQueryHandler.

Kotlin

// Projection array. Creating indices for this array instead of doing
// dynamic lookups improves performance.
private val EVENT_PROJECTION: Array<String> = arrayOf(
        CalendarContract.Calendars._ID,                     // 0
        CalendarContract.Calendars.ACCOUNT_NAME,            // 1
        CalendarContract.Calendars.CALENDAR_DISPLAY_NAME,   // 2
        CalendarContract.Calendars.OWNER_ACCOUNT            // 3
)

// The indices for the projection array above.
private const val PROJECTION_ID_INDEX: Int = 0
private const val PROJECTION_ACCOUNT_NAME_INDEX: Int = 1
private const val PROJECTION_DISPLAY_NAME_INDEX: Int = 2
private const val PROJECTION_OWNER_ACCOUNT_INDEX: Int = 3

Java

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

Im nächsten Teil des Beispiels erstellen Sie die Abfrage. Durch die Auswahl werden die Kriterien für die Abfrage festgelegt. In diesem Beispiel wird in der Abfrage nach Kalendern gesucht, die die ACCOUNT_NAME „hera@beispiel.de“, die ACCOUNT_TYPE „beispiel.de“ und die OWNER_ACCOUNT „hera@beispiel.de“ enthalten. Wenn Sie alle Kalender sehen möchten, die ein Nutzer aufgerufen hat, nicht nur die Kalender, die ihm gehören, lassen Sie OWNER_ACCOUNT weg. Die Abfrage gibt ein Cursor-Objekt zurück, mit dem Sie den von der Datenbankabfrage zurückgegebenen Ergebnissatz durchsuchen können. Weitere Informationen zur Verwendung von Abfragen bei Contentanbietern finden Sie unter Contentanbieter.

Kotlin

// Run query
val uri: Uri = CalendarContract.Calendars.CONTENT_URI
val selection: String = "((${CalendarContract.Calendars.ACCOUNT_NAME} = ?) AND (" +
        "${CalendarContract.Calendars.ACCOUNT_TYPE} = ?) AND (" +
        "${CalendarContract.Calendars.OWNER_ACCOUNT} = ?))"
val selectionArgs: Array<String> = arrayOf("hera@example.com", "com.example", "hera@example.com")
val cur: Cursor = contentResolver.query(uri, EVENT_PROJECTION, selection, selectionArgs, null)

Java

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

Im nächsten Abschnitt wird der Cursor verwendet, um den Ergebnissatz durchzugehen. Dabei werden die Konstanten verwendet, die zu Beginn des Beispiels festgelegt wurden, um die Werte für jedes Feld zurückzugeben.

Kotlin

// Use the cursor to step through the returned records
while (cur.moveToNext()) {
    // Get the field values
    val calID: Long = cur.getLong(PROJECTION_ID_INDEX)
    val displayName: String = cur.getString(PROJECTION_DISPLAY_NAME_INDEX)
    val accountName: String = cur.getString(PROJECTION_ACCOUNT_NAME_INDEX)
    val ownerName: String = cur.getString(PROJECTION_OWNER_ACCOUNT_INDEX)
    // Do something with the values...
}

Java

// 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...

   ...
}

Kalender ändern

Wenn Sie einen Kalender aktualisieren möchten, können Sie die _ID des Kalenders entweder als angehängte ID an den Uri (withAppendedId()) oder als erstes Auswahlelement angeben. Die Auswahl sollte mit "_id=?" beginnen und die erste selectionArg sollte die _ID des Kalenders sein. Du kannst Aktualisierungen auch vornehmen, indem du die ID im URI codierst. In diesem Beispiel wird der Anzeigename eines Kalenders mithilfe des (withAppendedId())-Ansatzes geändert:

Kotlin

const val DEBUG_TAG: String = "MyActivity"
...
val calID: Long = 2
val values = ContentValues().apply {
    // The new display name for the calendar
    put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, "Trevor's Calendar")
}
val updateUri: Uri = ContentUris.withAppendedId(CalendarContract.Calendars.CONTENT_URI, calID)
val rows: Int = contentResolver.update(updateUri, values, null, null)
Log.i(DEBUG_TAG, "Rows updated: $rows")

Java

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

Kalender einfügen

Kalender sollten hauptsächlich über einen Synchronisierungsadapter verwaltet werden. Daher sollten Sie neue Kalender nur als Synchronisierungsadapter einfügen. In der Regel können Anwendungen nur oberflächliche Änderungen an Kalendern vornehmen, z. B. den Anzeigenamen ändern. Wenn eine Anwendung einen lokalen Kalender erstellen muss, kann sie die Kalendereinfügung als Synchronisierungsadapter mit einer ACCOUNT_TYPE von ACCOUNT_TYPE_LOCAL ausführen. ACCOUNT_TYPE_LOCAL ist ein spezieller Kontotyp für Kalender, die nicht mit einem Gerätekonto verknüpft sind. Kalender dieses Typs werden nicht mit einem Server synchronisiert. Weitere Informationen zu Synchronisatoren finden Sie unter Synchronisatoren.

Tabelle mit Ereignissen

Die Tabelle CalendarContract.Events enthält Details zu einzelnen Ereignissen. Wenn eine Anwendung Ereignisse hinzufügen, aktualisieren oder löschen möchte, muss sie die Berechtigung WRITE_CALENDAR in ihrer Manifestdatei angeben.

Die folgenden Ereignisspalten können sowohl von einer Anwendung als auch von einem Synchronisierungsadapter geschrieben werden. Eine vollständige Liste der unterstützten Felder findest du in der CalendarContract.Events-Referenz.

Konstante Beschreibung
CALENDAR_ID Die _ID des Kalenders, zu dem der Termin gehört.
ORGANIZER E-Mail-Adresse des Organisators (Eigentümers) des Termins.
TITLE Der Titel der Veranstaltung.
EVENT_LOCATION Der Ort, an dem die Veranstaltung stattfindet.
DESCRIPTION Die Beschreibung des Ereignisses.
DTSTART Der Beginn des Ereignisses in UTC-Millisekunden seit der Epoche.
DTEND Die Zeit, zu der das Ereignis endet, in Millisekunden nach der Epoche (UTC).
EVENT_TIMEZONE Die Zeitzone für das Ereignis.
EVENT_END_TIMEZONE Die Zeitzone für das Ende des Termins.
DURATION Die Dauer des Ereignisses im RFC5545-Format. Ein Wert von "PT1H" gibt beispielsweise an, dass das Ereignis eine Stunde dauern soll, und ein Wert von "P2W" eine Dauer von zwei Wochen.
ALL_DAY Ein Wert von 1 gibt an, dass dieses Ereignis den ganzen Tag dauert, wie in der lokalen Zeitzone definiert. Ein Wert von 0 gibt an, dass es sich um ein regelmäßiges Ereignis handelt, das zu jeder Tageszeit beginnen und enden kann.
RRULE Die Wiederholungsregel für das Ereignisformat. Beispiel: "FREQ=WEEKLY;COUNT=10;WKST=SU". Weitere Beispiele finden Sie hier.
RDATE Die Wiederholungsdaten des Ereignisses. Normalerweise wird RDATE in Kombination mit RRULE verwendet, um eine Gesamtheit sich wiederholender Vorkommen zu definieren. Weitere Informationen finden Sie in der RFC 5545-Spezifikation.
AVAILABILITY Ob dieses Ereignis als geschäftige Zeit gilt oder als verfügbare Zeit, die überplant werden kann.
GUESTS_CAN_MODIFY Ob Gäste den Termin bearbeiten können.
GUESTS_CAN_INVITE_OTHERS Ob Gäste andere Gäste einladen können.
GUESTS_CAN_SEE_GUESTS Ob Gäste die Teilnehmerliste sehen können.

Hinzufügen von Terminen

Wenn Ihre Anwendung ein neues Ereignis einfügt, empfehlen wir die Verwendung eines INSERT-Intents, wie unter Ereignisse mithilfe eines Intents einfügen beschrieben. Sie können Ereignisse aber auch direkt einfügen. In diesem Abschnitt wird beschrieben, wie das geht.

Beachten Sie beim Einfügen eines neuen Ereignisses die folgenden Regeln:

Hier ist ein Beispiel für das Einfügen eines Ereignisses. Dies wird der Einfachheit halber im UI-Thread ausgeführt. In der Praxis sollten Einfügungen und Aktualisierungen in einem asynchronen Thread erfolgen, um die Aktion in einen Hintergrundthread zu verschieben. Weitere Informationen finden Sie unter AsyncQueryHandler.

Kotlin

val calID: Long = 3
val startMillis: Long = Calendar.getInstance().run {
    set(2012, 9, 14, 7, 30)
    timeInMillis
}
val endMillis: Long = Calendar.getInstance().run {
    set(2012, 9, 14, 8, 45)
    timeInMillis
}
...

val values = ContentValues().apply {
    put(CalendarContract.Events.DTSTART, startMillis)
    put(CalendarContract.Events.DTEND, endMillis)
    put(CalendarContract.Events.TITLE, "Jazzercise")
    put(CalendarContract.Events.DESCRIPTION, "Group workout")
    put(CalendarContract.Events.CALENDAR_ID, calID)
    put(CalendarContract.Events.EVENT_TIMEZONE, "America/Los_Angeles")
}
val uri: Uri = contentResolver.insert(CalendarContract.Events.CONTENT_URI, values)

// get the event ID that is the last element in the Uri
val eventID: Long = uri.lastPathSegment.toLong()
//
// ... do something with event ID
//
//

Java

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

Hinweis:In diesem Beispiel wird die Ereignis-ID nach dem Erstellen des Ereignisses erfasst. Das ist die einfachste Möglichkeit, eine Ereignis-ID zu erhalten. Sie benötigen die Ereignis-ID häufig, um andere Kalenderaktionen auszuführen, z. B. um einem Termin Teilnehmer oder Erinnerungen hinzuzufügen.

Updates

Wenn Nutzer in Ihrer App ein Ereignis bearbeiten sollen, empfehlen wir die Verwendung eines EDIT-Intents, wie unter Ereignisse mit einem Intent bearbeiten beschrieben. Bei Bedarf können Sie Termine aber auch direkt bearbeiten. Wenn Sie ein Ereignis aktualisieren möchten, können Sie die _ID des Ereignisses entweder als angehängte ID an den URI (withAppendedId()) oder als erstes Auswahlelement angeben. Die Auswahl sollte mit "_id=?" beginnen und die erste selectionArg sollte die _ID des Ereignisses sein. Sie können Aktualisierungen auch mit einer Auswahl ohne ID vornehmen. Hier ist ein Beispiel für die Aktualisierung eines Ereignisses: Dabei wird der Titel des Termins mit dem withAppendedId()-Ansatz geändert:

Kotlin

val DEBUG_TAG = "MyActivity"
...
val eventID: Long = 188
...
val values = ContentValues().apply {
    // The new title for the event
    put(CalendarContract.Events.TITLE, "Kickboxing")
}
val updateUri: Uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID)
val rows: Int = contentResolver.update(updateUri, values, null, null)
Log.i(DEBUG_TAG, "Rows updated: $rows")

Java

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 = cr.update(updateUri, values, null, null);
Log.i(DEBUG_TAG, "Rows updated: " + rows);

Termine löschen

Sie können ein Ereignis entweder anhand seiner _ID als angehängte ID im URI oder mithilfe der Standardauswahl löschen. Wenn Sie eine angehängte ID verwenden, können Sie keine Auswahl treffen. Es gibt zwei Versionen von „delete“: als Anwendung und als Synchronisierungsadapter. Beim Löschen einer Anwendung wird in der Spalte deleted der Wert 1 festgelegt. Dieses Flag teilt dem Synchronisierungsadapter mit, dass die Zeile gelöscht wurde und dass diese Löschung an den Server weitergegeben werden soll. Wenn ein Synchronisierungsadapter gelöscht wird, werden das Ereignis und alle zugehörigen Daten aus der Datenbank entfernt. Hier ist ein Beispiel für eine Anwendung, die ein Ereignis über seine _ID löscht:

Kotlin

val DEBUG_TAG = "MyActivity"
...
val eventID: Long = 201
...
val deleteUri: Uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID)
val rows: Int = contentResolver.delete(deleteUri, null, null)
Log.i(DEBUG_TAG, "Rows deleted: $rows")

Java

private static final String DEBUG_TAG = "MyActivity";
...
long eventID = 201;
...
ContentResolver cr = getContentResolver();
Uri deleteUri = null;
deleteUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
int rows = cr.delete(deleteUri, null, null);
Log.i(DEBUG_TAG, "Rows deleted: " + rows);

Tabelle „Teilnehmer“

Jede Zeile der Tabelle CalendarContract.Attendees steht für einen einzelnen Teilnehmer oder Gast einer Veranstaltung. Wenn du query() aufrufst, wird eine Liste der Teilnehmer für die Veranstaltung mit der angegebenen EVENT_ID zurückgegeben. Diese EVENT_ID muss mit der _ID eines bestimmten Ereignisses übereinstimmen.

In der folgenden Tabelle sind die beschreibbaren Felder aufgeführt. Wenn Sie einen neuen Teilnehmer einfügen, müssen Sie alle Teilnehmer mit Ausnahme von ATTENDEE_NAME angeben.

Konstante Beschreibung
EVENT_ID Die ID des Ereignisses.
ATTENDEE_NAME Der Name des Teilnehmers.
ATTENDEE_EMAIL Die E-Mail-Adresse des Teilnehmers.
ATTENDEE_RELATIONSHIP

Die Beziehung des Teilnehmers zur Veranstaltung. Eine der folgenden Optionen:

ATTENDEE_TYPE

Der Teilnehmertyp. Eine der folgenden Optionen:

ATTENDEE_STATUS

Der Teilnahmestatus des Gasts. Eine der folgenden Optionen:

Teilnehmer hinzufügen

In diesem Beispiel wird einem Termin ein einzelner Teilnehmer hinzugefügt. Beachten Sie, dass EVENT_ID erforderlich ist:

Kotlin

val eventID: Long = 202
...
val values = ContentValues().apply {
    put(CalendarContract.Attendees.ATTENDEE_NAME, "Trevor")
    put(CalendarContract.Attendees.ATTENDEE_EMAIL, "trevor@example.com")
    put(
        CalendarContract.Attendees.ATTENDEE_RELATIONSHIP,
        CalendarContract.Attendees.RELATIONSHIP_ATTENDEE
    )
    put(CalendarContract.Attendees.ATTENDEE_TYPE, CalendarContract.Attendees.TYPE_OPTIONAL)
    put(
        CalendarContract.Attendees.ATTENDEE_STATUS,
        CalendarContract.Attendees.ATTENDEE_STATUS_INVITED
    )
    put(CalendarContract.Attendees.EVENT_ID, eventID)
}
val uri: Uri = contentResolver.insert(CalendarContract.Attendees.CONTENT_URI, values)

Java

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

Tabelle „Erinnerungen“

Jede Zeile der Tabelle CalendarContract.Reminders steht für eine einzelne Erinnerung für ein Ereignis. Wenn Sie query() aufrufen, wird eine Liste von Erinnerungen für das Ereignis mit dem angegebenen EVENT_ID zurückgegeben.

In der folgenden Tabelle sind die beschreibbaren Felder für Erinnerungen aufgeführt. Sie müssen alle angegeben werden, wenn Sie eine neue Erinnerung einfügen. Synchronadapter geben die von ihnen unterstützten Arten von Erinnerungen in der Tabelle CalendarContract.Calendars an. Weitere Informationen finden Sie unter ALLOWED_REMINDERS.

Konstante Beschreibung
EVENT_ID Die ID des Ereignisses.
MINUTES Die Minuten vor dem Ereignis, zu dem die Erinnerung ausgelöst werden soll.
METHOD

Die Weckmethode, die auf dem Server festgelegt ist. Eine der folgenden Optionen:

Erinnerungen erstellen

In diesem Beispiel wird einem Termin eine Erinnerung hinzugefügt. Die Erinnerung wird 15 Minuten vor dem Termin ausgelöst.

Kotlin

val eventID: Long = 221
...
val values = ContentValues().apply {
    put(CalendarContract.Reminders.MINUTES, 15)
    put(CalendarContract.Reminders.EVENT_ID, eventID)
    put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT)
}
val uri: Uri = contentResolver.insert(CalendarContract.Reminders.CONTENT_URI, values)

Java

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

Tabelle „Instanzen“

Die Tabelle CalendarContract.Instances enthält die Start- und Endzeit für die Vorkommnisse eines Ereignisses. Jede Zeile in dieser Tabelle steht für ein einzelnes Ereignis. Die Tabelle „instances“ ist nicht beschreibbar und bietet nur eine Möglichkeit, Ereignisvorkommnisse abzufragen.

In der folgenden Tabelle sind einige der Felder aufgeführt, die Sie für eine Instanz abfragen können. Die Zeitzone wird durch KEY_TIMEZONE_TYPE und KEY_TIMEZONE_INSTANCES definiert.

Konstante Beschreibung
BEGIN Der Beginn der Instanz in Millisekunden nach UTC.
END Die Endzeit der Instanz in Millisekunden (UTC).
END_DAY Der julianische Endtag der Instanz, bezogen auf die Zeitzone des Kalenders.
END_MINUTE Die Endzeit der Instanz, gemessen ab Mitternacht in der Zeitzone von Google Kalender.
EVENT_ID Der _ID des Ereignisses für diese Instanz.
START_DAY Der Julianische Starttag der Instanz bezogen auf die Zeitzone des Kalenders.
START_MINUTE Die Minute des Beginns der Instanz, gemessen ab Mitternacht, bezogen auf die Zeitzone des Kalenders.

Tabelle „instances“ abfragen

Wenn Sie die Tabelle „Instances“ abfragen möchten, müssen Sie im URI einen Zeitraum für die Abfrage angeben. In diesem Beispiel erhält CalendarContract.Instances über die Implementierung der CalendarContract.EventsColumns-Oberfläche Zugriff auf das Feld TITLE. Mit anderen Worten: TITLE wird über eine Datenbankansicht zurückgegeben, nicht durch Abfragen der Rohtabelle CalendarContract.Instances.

Kotlin

const val DEBUG_TAG: String = "MyActivity"
val INSTANCE_PROJECTION: Array<String> = arrayOf(
        CalendarContract.Instances.EVENT_ID, // 0
        CalendarContract.Instances.BEGIN, // 1
        CalendarContract.Instances.TITLE // 2
)

// The indices for the projection array above.
const val PROJECTION_ID_INDEX: Int = 0
const val PROJECTION_BEGIN_INDEX: Int = 1
const val PROJECTION_TITLE_INDEX: Int = 2

// Specify the date range you want to search for recurring
// event instances
val startMillis: Long = Calendar.getInstance().run {
    set(2011, 9, 23, 8, 0)
    timeInMillis
}
val endMillis: Long = Calendar.getInstance().run {
    set(2011, 10, 24, 8, 0)
    timeInMillis
}

// The ID of the recurring event whose instances you are searching
// for in the Instances table
val selection: String = "${CalendarContract.Instances.EVENT_ID} = ?"
val selectionArgs: Array<String> = arrayOf("207")

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

// Submit the query
val cur: Cursor = contentResolver.query(
        builder.build(),
        INSTANCE_PROJECTION,
        selection,
        selectionArgs, null
)
while (cur.moveToNext()) {
    // Get the field values
    val eventID: Long = cur.getLong(PROJECTION_ID_INDEX)
    val beginVal: Long = cur.getLong(PROJECTION_BEGIN_INDEX)
    val title: String = cur.getString(PROJECTION_TITLE_INDEX)

    // Do something with the values.
    Log.i(DEBUG_TAG, "Event: $title")
    val calendar = Calendar.getInstance().apply {
        timeInMillis = beginVal
    }
    val formatter = SimpleDateFormat("MM/dd/yyyy")
    Log.i(DEBUG_TAG, "Date: ${formatter.format(calendar.time)}")
}

Java

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

Kalender-Intents

Ihre Anwendung benötigt keine Berechtigungen zum Lesen und Schreiben von Kalenderdaten. Stattdessen kann sie Intents verwenden, die von der Kalender-App von Android unterstützt werden, um Lese- und Schreibvorgänge an diese App weiterzuleiten. In der folgenden Tabelle sind die vom Kalenderanbieter unterstützten Intents aufgeführt:

Aktion URI Beschreibung Extras

VIEW

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

Sie können den URI auch mit CalendarContract.CONTENT_URI referenzieren. Ein Beispiel für die Verwendung dieses Intents finden Sie unter Intents zum Ansehen von Kalenderdaten verwenden.
Kalender für die in <ms_since_epoch> angegebene Zeit öffnen. Keine.

VIEW

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

Sie können den URI auch mit Events.CONTENT_URI referenzieren. Ein Beispiel für die Verwendung dieses Intents finden Sie unter Intents zum Ansehen von Kalenderdaten verwenden.
Rufen Sie das Ereignis auf, das durch <event_id> angegeben ist. CalendarContract.EXTRA_EVENT_BEGIN_TIME


CalendarContract.EXTRA_EVENT_END_TIME
EDIT

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

Sie können den URI auch mit Events.CONTENT_URI referenzieren. Ein Beispiel für die Verwendung dieses Intents finden Sie unter Ereignisse mit einem Intent bearbeiten.
Bearbeiten Sie das Ereignis, das durch <event_id> angegeben ist. CalendarContract.EXTRA_EVENT_BEGIN_TIME


CalendarContract.EXTRA_EVENT_END_TIME
EDIT

INSERT

content://com.android.calendar/events

Sie können den URI auch mit Events.CONTENT_URI referenzieren. Ein Beispiel für die Verwendung dieses Intents finden Sie unter Intent zum Einfügen eines Ereignisses verwenden.
Erstellen Sie einen Termin. Alle in der folgenden Tabelle aufgeführten Extras.

In der folgenden Tabelle sind die vom Kalenderanbieter unterstützten Intent-Extras aufgeführt:

Intent Extra Beschreibung
Events.TITLE Name für das Ereignis.
CalendarContract.EXTRA_EVENT_BEGIN_TIME Beginn des Ereignisses in Millisekunden ab der Epoche.
CalendarContract.EXTRA_EVENT_END_TIME Endzeit des Ereignisses in Millisekunden seit der Epoche.
CalendarContract.EXTRA_EVENT_ALL_DAY Ein boolescher Wert, der angibt, dass ein Ereignis den ganzen Tag dauert. Der Wert kann true oder false sein.
Events.EVENT_LOCATION Ort des Ereignisses
Events.DESCRIPTION Beschreibung der Veranstaltung.
Intent.EXTRA_EMAIL E-Mail-Adressen der einzuladenden Personen als durch Kommas getrennte Liste.
Events.RRULE Die Wiederholungsregel für den Termin.
Events.ACCESS_LEVEL Ob es sich um eine private oder öffentliche Veranstaltung handelt.
Events.AVAILABILITY Ob dieses Ereignis als belegte Zeit gilt oder als verfügbare Zeit, die überplant werden kann.

In den folgenden Abschnitten wird beschrieben, wie Sie diese Intents verwenden.

Intent verwenden, um ein Ereignis einzufügen

Mit der INSERT-Intent kann Ihre Anwendung die Aufgabe zum Einfügen von Terminen an den Kalender selbst weitergeben. Bei diesem Ansatz muss die Berechtigung WRITE_CALENDAR nicht einmal in der Manifestdatei Ihrer Anwendung enthalten sein.

Wenn Nutzer eine Anwendung ausführen, die diesen Ansatz verwendet, werden sie von der Anwendung zum Kalender weitergeleitet, um den Termin fertig hinzuzufügen. Bei der INSERT-Intention werden zusätzliche Felder verwendet, um ein Formular vorab mit den Details des Termins im Kalender auszufüllen. Nutzer können den Termin dann absagen, das Formular bei Bedarf bearbeiten oder den Termin in ihrem Kalender speichern.

Hier ist ein Code-Snippet, mit dem ein Ereignis für den 19. Januar 2012 von 7:30 bis 8:30 Uhr geplant wird. Beachten Sie bei diesem Code-Snippet Folgendes:

Kotlin

val startMillis: Long = Calendar.getInstance().run {
    set(2012, 0, 19, 7, 30)
    timeInMillis
}
val endMillis: Long = Calendar.getInstance().run {
    set(2012, 0, 19, 8, 30)
    timeInMillis
}
val intent = Intent(Intent.ACTION_INSERT)
        .setData(CalendarContract.Events.CONTENT_URI)
        .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, startMillis)
        .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endMillis)
        .putExtra(CalendarContract.Events.TITLE, "Yoga")
        .putExtra(CalendarContract.Events.DESCRIPTION, "Group class")
        .putExtra(CalendarContract.Events.EVENT_LOCATION, "The gym")
        .putExtra(CalendarContract.Events.AVAILABILITY, CalendarContract.Events.AVAILABILITY_BUSY)
        .putExtra(Intent.EXTRA_EMAIL, "rowan@example.com,trevor@example.com")
startActivity(intent)

Java

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

Ereignis mit einem Intent bearbeiten

Sie können ein Ereignis direkt aktualisieren, wie unter Ereignisse aktualisieren beschrieben. Wenn Sie den Intent EDIT verwenden, kann eine Anwendung, die keine Berechtigung hat, jedoch die Bearbeitung von Terminen an die Kalenderanwendung übergeben. Wenn Nutzer die Bearbeitung des Termins im Kalender abgeschlossen haben, werden sie zur ursprünglichen Anwendung zurückgeleitet.

Hier ist ein Beispiel für einen Intent, der einen neuen Titel für ein bestimmtes Ereignis festlegt und Nutzer den Termin im Kalender bearbeiten können.

Kotlin

val eventID: Long = 208
val uri: Uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID)
val intent = Intent(Intent.ACTION_EDIT)
        .setData(uri)
        .putExtra(CalendarContract.Events.TITLE, "My New Title")
startActivity(intent)

Java

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

Intents zum Ansehen von Kalenderdaten verwenden

Der Kalenderanbieter bietet zwei Möglichkeiten, die VIEW-Intention zu verwenden:

  • Öffnen Sie den Kalender auf ein bestimmtes Datum.
  • So rufen Sie ein Ereignis auf:

Hier ein Beispiel, wie Sie den Kalender auf ein bestimmtes Datum öffnen:

Kotlin

val startMillis: Long
...
val builder: Uri.Builder = CalendarContract.CONTENT_URI.buildUpon()
        .appendPath("time")
ContentUris.appendId(builder, startMillis)
val intent = Intent(Intent.ACTION_VIEW)
        .setData(builder.build())
startActivity(intent)

Java

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

Hier ein Beispiel für das Öffnen eines Ereignisses zur Ansicht:

Kotlin

val eventID: Long = 208
...
val uri: Uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID)
val intent = Intent(Intent.ACTION_VIEW).setData(uri)
startActivity(intent)

Java

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

Synchronisierungsadapter

Es gibt nur geringfügige Unterschiede bei der Art und Weise, wie eine Anwendung und ein Synchronisierungsadapter auf den Kalenderanbieter zugreifen:

  • Ein Synchronisierungsadapter muss angeben, dass es sich um einen Synchronisierungsadapter handelt, indem CALLER_IS_SYNCADAPTER auf true festgelegt wird.
  • Ein Synchronisierungsadapter muss ACCOUNT_NAME und ACCOUNT_TYPE als Abfrageparameter im URI angeben.
  • Ein Synchronisierungsadapter hat Schreibzugriff auf mehr Spalten als eine Anwendung oder ein Widget. Eine Anwendung kann beispielsweise nur einige Eigenschaften eines Kalenders ändern, z. B. seinen Namen, seinen Anzeigenamen, die Sichtbarkeitseinstellung und ob der Kalender synchronisiert wird. Ein Synchronisierungsadapter kann dagegen nicht nur auf diese Spalten, sondern auch auf viele andere zugreifen, z. B. auf Kalenderfarbe, Zeitzone, Zugriffsebene und Standort. Ein Synchronisierungsadapter ist jedoch auf die angegebenen ACCOUNT_NAME und ACCOUNT_TYPE beschränkt.

Hier ist eine Hilfsmethode, mit der Sie einen URI für die Verwendung mit einem Synchronisierungsadapter zurückgeben können:

Kotlin

fun asSyncAdapter(uri: Uri, account: String, accountType: String): Uri {
    return uri.buildUpon()
            .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true")
            .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_NAME, account)
            .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_TYPE, accountType).build()
}

Java

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