Omówienie dostawcy kalendarza

Dostawca kalendarza to repozytorium wydarzeń w kalendarzu użytkownika. Interfejs Calendar Provider API umożliwia wykonywanie zapytań, wstawianie, aktualizowanie i usuwanie w kalendarzach, wydarzeniach, uczestnikach, przypomnieniach itd.

Z interfejsu Calendar Provider API mogą korzystać aplikacje i adaptery synchronizacji. reguły różnią się w zależności od typu programu, który wykonuje połączenia. Ten dokument polega głównie na używaniu interfejsu Calendar Provider API jako aplikacji. Informacje o tym, czym różnią się adaptery synchronizacji, znajdziesz w artykule Adaptery synchronizacji.

Zwykle do odczytu lub zapisu danych kalendarza plik manifestu aplikacji musi musi obejmować odpowiednie uprawnienia opisane w sekcji Użytkownik Uprawnienia. Aby ułatwić wykonywanie typowych operacji, dostawca kalendarza udostępnia zestaw intencji opisanych w artykule Intencje dotyczące kalendarza. Te intencje przekierowują użytkowników do aplikacji Kalendarz, aby wstawiać, wyświetlać i edytować wydarzenia. Użytkownik wchodzi w interakcję z aplikacją Kalendarz, a następnie spowoduje powrót do pierwotnej aplikacji. Dzięki temu aplikacja nie musi prosić o uprawnienia, nie musi też udostępniać interfejsu użytkownika do wyświetlania ani tworzenia zdarzeń.

Podstawy

Dostawcy treści przechowują dane i udostępniają je aplikacji. Dostawcy treści oferowany przez platformę Androida (w tym dostawcę Kalendarza) zwykle udostępniają dane w postaci zbioru tabel na podstawie relacyjny model bazy danych, w którym każdy wiersz to rekord, a każda kolumna zawiera dane określonego typu i znaczenia. Dzięki interfejsowi Calendar Provider API aplikacje i adaptery synchronizacji mogą uzyskać uprawnienia do odczytu/zapisu w tabelach bazy danych, które zawierają dane z kalendarza użytkownika.

Każdy dostawca treści ujawnia publiczny identyfikator URI (opakowany jako Uri obiektu), który jednoznacznie identyfikuje zbiór danych. Dostawca treści, który zarządza wieloma zbiorami danych (wiele tabel), udostępnia dla każdego z nich osobny adres URI. Wszystkie URI dostawców zaczynają się od ciągu „content://”. Ten wskazuje, że dane są kontrolowane przez dostawcę treści. Dostawca kalendarza definiuje stałe dla URI dla każdej ze swoich klas (tabel). Te URI mają format <class>.CONTENT_URI. Na przykład: Events.CONTENT_URI.

Rysunek 1 przedstawia model danych dostawcy kalendarza w postaci graficznej. Pokazuje ona główne tabele i pola, które je ze sobą łączą.

Model danych dostawcy kalendarza

Rysunek 1. Model danych dostawcy kalendarza.

Użytkownik może mieć wiele kalendarzy, a różne kalendarze mogą być powiązane z różnymi typami kont (Kalendarz Google, Exchange itp.).

CalendarContract definiuje model danych kalendarza i informacje związane z wydarzeniami. Dane te są przechowywane w wielu tabelach wymienionych poniżej.

Tabela (klasa) Opis

CalendarContract.Calendars

Ta tabela zawiera do informacji z kalendarza. Każdy wiersz w tej tabeli zawiera informacje o pojedynczym kalendarzu, takie jak nazwa, kolor, informacje o synchronizacji itp.
CalendarContract.Events Zawiera ona informacji na temat konkretnego zdarzenia. Każdy wiersz w tej tabeli zawiera informacje na temat wydarzenie – na przykład tytuł, lokalizacja, godzina rozpoczęcia, koniec. czas i tak dalej. Zdarzenie może mieć miejsce jednorazowo lub może występować wiele razy. Uczestnicy, przypomnienia i rozszerzone właściwości są przechowywane w osobnych tabelach. Każdy z nich ma uprawnienia EVENT_ID odwołujący się do _ID w tabeli Zdarzenia.
CalendarContract.Instances Ta tabela zawiera czas rozpoczęcia i zakończenia każdego wystąpienia zdarzenia. Każdy wiersz w tej tabeli odpowiada pojedynczemu wystąpieniu zdarzenia. W przypadku jednorazowych zdarzeń występuje mapowanie 1:1 wydarzeń na wystąpienia. W przypadku zdarzeń cyklicznych automatycznie generowane są liczne wiersze odpowiadające wielu wystąpieniom danego zdarzenia.
CalendarContract.Attendees Zawiera ona informacje o uczestniku wydarzenia (gościu). Każdy wiersz odpowiada jednemu gościowi . Określa typ gościa i odpowiedź o jego obecności dla danego wydarzenia.
CalendarContract.Reminders Ta tabela zawiera dane o alertach i powiadomieniach. Każdy wiersz odpowiada jednemu alarmowi dotyczącemu zdarzenia. Jedno wydarzenie może mieć wiele przypomnień. Maksymalna liczba przypomnień na wydarzenie jest określona w parametrye MAX_REMINDERS, który jest ustawiany przez adapter synchronizacji będący właścicielem danego kalendarza. Przypomnienia są określane w minutach przed wydarzeniem pozwalają też określić sposób powiadamiania użytkownika.

Interfejs Calendar Provider API został zaprojektowany tak, aby był elastyczny i wydajny. Na Ważne jest jednak zapewnienie użytkownikom dobrych wrażeń chronić integralność kalendarza i jego danych. W tym celu o czym warto pamiętać podczas korzystania z interfejsu API:

  • Wstawianie, aktualizowanie i wyświetlanie wydarzeń w kalendarzu. Aby bezpośrednio wstawiać, modyfikować i odczytywać wydarzenia z poziomu dostawcy kalendarza, potrzebujesz odpowiednich uprawnień. Jeśli jednak nie tworzysz pełnej aplikacji kalendarza ani adaptera synchronizacji, nie musisz prosić o te uprawnienia. Zamiast tego możesz użyć intencji obsługiwanych przez aplikację Kalendarz na Androidzie, aby przekazać tej aplikacji operacje odczytu i zapisu. Gdy używasz intencji, aplikacja wysyła użytkowników do aplikacji Kalendarz w celu wykonania oczekiwanej operacji w wstępnie wypełnionym formularzu. Po zakończeniu wracają do aplikacji. Gdy zaprojektujesz aplikację do wykonywania typowych operacji w Kalendarzu, Oferujesz użytkownikom spójny i niezawodny interfejs. To jest zalecane działania. Więcej informacji znajdziesz w artykule Kalendarz Intencje.
  • Synchroniz adaptery. Adapter synchronizacji synchronizuje dane kalendarza na urządzeniu użytkownika z innym serwerem lub źródłem danych. W tabelach CalendarContract.Calendars i CalendarContract.Events znajdują się kolumny zarezerwowane dla adapterów synchronizacji. Dostawca i aplikacje nie powinny ich modyfikować. W rzeczywistości nie są to widoczne, chyba że korzystasz z nich jako adapter synchronizacji. Więcej informacji na temat: i adaptery synchronizacji: patrz Adaptery synchronizacji.

Uprawnienia użytkowników

Aby odczytywać dane z kalendarza, aplikacja musi zawierać w pliku manifestu uprawnienie READ_CALENDAR. Musi ona zawierać uprawnienia WRITE_CALENDAR do usuwania, wstawiania i aktualizowania danych kalendarza:

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

Tabela Kalendarze

Tabela CalendarContract.Calendars zawiera szczegółowe informacje o poszczególnych kalendarzach. W tych kolumnach Kalendarza można zapisywać dane zarówno w aplikacji, jak i w adapterze synchronizacji. Pełną listę obsługiwanych pól znajdziesz w Odwołanie do: CalendarContract.Calendars.

Stała Opis
NAME Nazwa kalendarza.
CALENDAR_DISPLAY_NAME Nazwa tego kalendarza wyświetlana użytkownikowi.
VISIBLE Wartość logiczna wskazująca, czy kalendarz ma być wyświetlany. O Wartość 0 oznacza, że wydarzenia powiązane z tym kalendarzem nie powinny być wyświetlane. Wartość 1 oznacza, że wydarzenia powiązane z tym kalendarzem powinny które mają być wyświetlane. Ta wartość wpływa na generowanie wierszy w tabeli CalendarContract.Instances.
SYNC_EVENTS Wartość logiczna wskazująca, czy kalendarz ma być synchronizowany i czy jego wydarzenia mają być przechowywane na urządzeniu. Wartość 0 oznacza nie synchronizuj tego kalendarza lub przechowywania zdarzeń na urządzeniu. Wartość 1 oznacza synchronizację wydarzeń dla tego kalendarza i przechowują zdarzenia na urządzeniu.

Uwzględnij rodzaj konta w przypadku wszystkich operacji

Jeśli wysyłasz zapytanie dotyczące Calendars.ACCOUNT_NAME, musisz też uwzględnić w wybranych kolumnach kolumnę Calendars.ACCOUNT_TYPE. To dlatego, że dane konto uważany za unikalny tylko ze względu na jego pole ACCOUNT_NAME i ACCOUNT_TYPE Wartość ACCOUNT_TYPE to ciąg znaków odpowiadający uwierzytelniającemu kontu, który został użyty podczas rejestracji konta w usłudze AccountManager. Istnieje też specjalny typ konta o nazwie ACCOUNT_TYPE_LOCAL, który służy do obsługi kalendarzy nieprzypisanych do konta urządzenia. ACCOUNT_TYPE_LOCAL konta nie otrzymują zsynchronizowano.

Wysyłanie zapytania do kalendarza

Oto przykład, który pokazuje, jak pobrać kalendarze należące do konkretnej osoby użytkownika. Dla uproszczenia w tym przykładzie operacja na zapytaniu jest przedstawiona wątek w interfejsie („wątek główny”). W praktyce należy to robić asynchronicznie w wątku, a nie w wątku głównym. Więcej dyskusji znajdziesz tutaj: Moduły ładowania. Jeśli nie tylko odczytujecie dane, ale je modyfikujecie, zapoznajcie się z artykułem 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;

W następnej części przykładu utworzysz zapytanie. Wybór określa kryteria zapytania. W tym przykładzie zapytanie szuka kalendarze z atrybutem ACCOUNT_NAME „hera@example.com”, ACCOUNT_TYPE „com.example” oraz OWNER_ACCOUNT „hera@example.com”. Jeśli chcesz zobaczyć wszystkie kalendarze, które użytkownik wyświetlił, a nie tylko te, które mu należą, pomiń parametr OWNER_ACCOUNT. Zapytanie zwraca Cursor obiekt, którego można używać do przemierzania zbioru wyników zwróconego przez bazę danych zapytania. Więcej o korzystaniu z zapytań w usługach dostawców treści Więcej informacji: Dostawcy treści.

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

W następnej sekcji kursor będzie służyć do przechodzenia przez zbiór wyników. Do zwracania wartości poszczególnych pól używa stałych wartości skonfigurowanych na początku przykładu.

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

   ...
}

Modyfikowanie kalendarza

Aby zaktualizować kalendarz, możesz podać _ID kalendarza jako dołączony identyfikator do Uri (withAppendedId()) lub jako pierwszy element wyboru. Wybór powinien zaczynać się od "_id=?" i pierwszego Wartość selectionArg powinna być wartością _ID kalendarza. Możesz też wprowadzać zmiany, kodując identyfikator w identyfikatorze URI. W tym przykładzie zmieniamy przy użyciu (withAppendedId()) podejście:

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

Wstawianie kalendarza

Kalendarze są zaprojektowane do zarządzania głównie przez adapter synchronizacji, więc nowe kalendarze należy wstawiać tylko jako adapter synchronizacji. W większości przypadków aplikacje mogą wprowadzać tylko powierzchowne zmiany w kalendarzach, takie jak zmiana wyświetlanej nazwy. Jeśli aplikacja musi utworzyć lokalny kalendarz, może to zrobić, wykonując wstawienie kalendarza jako adapter synchronizacji, używając ACCOUNT_TYPE ACCOUNT_TYPE_LOCAL. ACCOUNT_TYPE_LOCALto specjalny typ konta przeznaczony do kalendarzy, które nie są powiązane z kontem urządzenia. Kalendarze tego typu nie są synchronizowane z serwerem. Dla o adapterach synchronizacji zawiera artykuł Adaptery synchronizacji.

Tabela zdarzeń

Tabela CalendarContract.Events zawiera szczegóły dla poszczególnych wydarzeń. Aby dodawać, aktualizować lub usuwać zdarzenia, aplikacja musi mieć w pliku manifestu uprawnienia WRITE_CALENDAR.

Poniższe kolumny Zdarzenia mogą zapisywać zarówno aplikację, jak i synchronizację przejściówkę. Pełną listę obsługiwanych pól znajdziesz w dokumentacji CalendarContract.Events.

Stała Opis
CALENDAR_ID _ID kalendarza, do którego należy wydarzenie.
ORGANIZER Adres e-mail organizatora (właściciela) wydarzenia.
TITLE Nazwa zdarzenia.
EVENT_LOCATION Miejsce, w którym odbywa się wydarzenie.
DESCRIPTION Opis zdarzenia.
DTSTART Czas rozpoczęcia zdarzenia w milisekundach UTC od początku epoki.
DTEND Czas zakończenia zdarzenia w milisekundach UTC od początku epoki.
EVENT_TIMEZONE Strefa czasowa wydarzenia.
EVENT_END_TIMEZONE Strefa czasowa określająca czas zakończenia wydarzenia.
DURATION Czas trwania zdarzenia w formacie RFC 5545. Na przykład wartość "PT1H" oznacza, że zdarzenie powinno trwać godzinę, a wartość "P2W" wskazuje czas trwania wynoszący 2 tygodnie.
ALL_DAY Wartość 1 oznacza, że wydarzenie zajmuje cały dzień, zgodnie z definicją lokalnej strefy czasowej. Wartość 0 oznacza zwykłe zdarzenie, które może się rozpocząć i zakończyć o dowolnej porze dnia.
RRULE Reguła powtarzania formatu zdarzenia. Dla: przykład: "FREQ=WEEKLY;COUNT=10;WKST=SU". Więcej przykładów znajdziesz tutaj.
RDATE daty powtarzania wydarzenia; Zwykle używasz konta RDATE w koniunkcji z RRULE do zdefiniowania zagregowanego zbioru do ich powtarzających się wystąpień. Więcej informacji znajdziesz w specyfikacji RFC5545.
AVAILABILITY Jeśli wydarzenie jest liczone jako czas wolny lub może być zaplanowano na później.
GUESTS_CAN_MODIFY Określa, czy goście mogą modyfikować wydarzenie.
GUESTS_CAN_INVITE_OTHERS czy goście mogą zapraszać innych gości.
GUESTS_CAN_SEE_GUESTS Określa, czy goście mogą wyświetlać listę uczestników.

Dodawanie wydarzeń

Gdy aplikacja wstawia nowe zdarzenie, zalecamy użycie INSERTintencji, zgodnie z opisem w sekcji Wstawianie zdarzenia za pomocą intencji. Jeśli jednak możesz wstawić zdarzenia bezpośrednio. Z tej sekcji dowiesz się, jak to zrobić.

Oto zasady wstawiania nowego zdarzenia:

Oto przykład wstawiania zdarzenia. Wykonuję tę czynność w interfejsie dla uproszczenia. W praktyce należy je wstawiać i aktualizować wątku asynchronicznego, by przenieść działanie do wątku w tle. Więcej Więcej informacji: 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
//
//

Uwaga: zobacz, jak w tym przykładzie pokazane jest zdarzenie. Identyfikator po utworzeniu wydarzenia. To najprostszy sposób na uzyskanie identyfikatora zdarzenia. Często potrzebują identyfikatora wydarzenia do wykonywania innych operacji w kalendarzu, na przykład dodania uczestników wydarzenia lub przypomnienia o wydarzeniu.

Aktualizacje

Jeśli aplikacja ma umożliwiać użytkownikowi edytowanie zdarzenia, zalecamy użycie EDITintencji, jak opisano w artykule Używanie intencji do edytowania zdarzenia. W razie potrzeby możesz jednak edytować zdarzenia bezpośrednio. Aby wykonać aktualizację jako zdarzenia, możesz określić _ID funkcji jako identyfikatora dołączonego do identyfikatora URI (withAppendedId()) lub jako pierwszy element wyboru. Wybór powinien zaczynać się od "_id=?" i pierwszego znaku Wartość selectionArg powinna być wartością _ID zdarzenia. Możesz też wprowadzić zmiany za pomocą selekcji bez identyfikatora. Oto przykład aktualizacji . Zmienia nazwę wydarzenia za pomocą podejścia withAppendedId():

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

Usuń wydarzenia

Zdarzenie możesz usunąć, podając jego _ID jako dołączony identyfikator w URI lub za pomocą standardowej selekcji. Jeśli używasz dołączonego identyfikatora, nie możesz też dokonać wyboru. Istnieją 2 wersje funkcji usuwania: jako aplikacja i jako adapter synchronizacji. Usunięcie aplikacji powoduje ustawienie kolumny deleted na wartość 1. Ta flaga informuje, adapter synchronizacji, że wiersz został usunięty i że to usunięcie powinno na serwer. Usunięcie adaptera synchronizacji powoduje usunięcie zdarzenia z wraz ze wszystkimi powiązanymi danymi. Oto przykład aplikacji usuwanie wydarzenia za pomocą jego _ID:

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

Tabela uczestników

Każdy wiersz w tabeli CalendarContract.Attendees reprezentuje pojedynczego uczestnika lub gościa wydarzenia. Łączę query() zwraca listę uczestników wydarzenia zdarzenie z danym EVENT_ID. Ten element EVENT_IDmusi być zgodny z elementem _ID konkretnego zdarzenia.

W tabeli poniżej znajdziesz listę pola do zapisu. Podczas wstawiania nowego uczestnika musisz uwzględnić wszystkich, z wyjątkiem ATTENDEE_NAME.

Stała Opis
EVENT_ID Identyfikator wydarzenia.
ATTENDEE_NAME Imię i nazwisko uczestnika.
ATTENDEE_EMAIL Adres e-mail uczestnika.
ATTENDEE_RELATIONSHIP

związek uczestnika z wydarzeniem; Jedno z tych:

ATTENDEE_TYPE

Typ uczestnika. Jedno z tych:

ATTENDEE_STATUS

Stan obecności uczestnika. Jedna z tych możliwości:

Dodawanie uczestników

Oto przykład dodania jednego uczestnika do wydarzenia. Pamiętaj, że parametr EVENT_ID jest wymagane:

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

Tabela przypomnień

Każdy wiersz w tabeli CalendarContract.Reminders odpowiada jednemu przypomnieniu o zdarzeniu. Łączę query() zwraca listę przypomnień dla zdarzenie z danym EVENT_ID

W tabeli poniżej znajdziesz pola przypomnień, które można zapisać. Wszystkie te elementy muszą być uwzględniane przy wstawianiu nowego przypomnienia. Pamiętaj, że adaptery synchronizacji określają obsługiwane przez nie typy przypomnień, w tabeli CalendarContract.Calendars. Zobacz ALLOWED_REMINDERS .

Stała Opis
EVENT_ID Identyfikator zdarzenia.
MINUTES Liczba minut przed wydarzeniem, w których przypomnienie ma się wyświetlić.
METHOD

Metoda alarmu skonfigurowana na serwerze. Jedna z tych możliwości:

Dodawaj przypomnienia

Ten przykład dodaje przypomnienie do wydarzenia. Przypomnienie zostanie wysłane 15 minut przed wydarzeniem.

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

Tabela instancji

Tabela CalendarContract.Instances zawiera czas rozpoczęcia i zakończenia wystąpień zdarzenia. Każdy wiersz w tej tabeli odpowiada pojedynczemu wystąpieniu zdarzenia. W tabeli instancji nie można zapisywać danych. Służy ona tylko do uzyskiwania informacji o wystąpieniach zdarzeń.

W tabeli poniżej znajdziesz listę niektórych pól, których możesz używać w zapytaniach dotyczących instancji. Pamiętaj, że strefa czasowa jest określana przez KEY_TIMEZONE_TYPE i KEY_TIMEZONE_INSTANCES.

Stała Opis
BEGIN Godzina rozpoczęcia instancji w milisekundach UTC.
END Czas zakończenia instancji w milisekundach UTC.
END_DAY Dzień juliański zakończenia instancji w zględzie strefy czasowej kalendarza.
END_MINUTE Minuta zakończenia wystąpienia liczona od północy w strefie czasowej Kalendarza.
EVENT_ID _ID zdarzenia w danym przypadku.
START_DAY Julijski dzień rozpoczęcia instancji określony względem strefy czasowej Kalendarza.
START_MINUTE Minuta rozpoczęcia instancji mierzona od północy w strefie czasowej Kalendarza.

Tworzenie zapytania do tabeli instancji

Aby wykonać zapytanie dotyczące tabeli instancji, musisz określić zakres czasowy dla tego zapytania w identyfikatorze URI. W tym przykładzie: CalendarContract.Instances uzyskuje dostęp do pola TITLE za pomocą parametru po wdrożeniu interfejsu CalendarContract.EventsColumns. Inaczej mówiąc, TITLE jest zwracana przez widoku bazy danych, a nie przez wysyłanie zapytań do tabeli nieprzetworzonej 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()));
    }
 }

Intencje dotyczące Kalendarza

Aplikacja nie musi mieć uprawnień do odczytywania i zapisywania danych z kalendarza. Może zamiast tego używać intencji obsługiwanych przez aplikację Kalendarz na Androidzie, aby przekazywać do niej operacje odczytu i zapisu. Poniższa tabela zawiera intencje obsługiwane przez dostawcę kalendarza:

Działanie URI Opis Dodatkowe treści

VIEW

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

Możesz też użyć URI z CalendarContract.CONTENT_URI. Przykład użycia tego zamiaru znajdziesz w artykule Używanie intencji do wyświetlania danych z kalendarza.
Otwórz kalendarz do godziny określonej przez: <ms_since_epoch>. Brak.

VIEW

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

Możesz też użyć URI z Events.CONTENT_URI. Przykład użycia tego zamiaru znajdziesz w artykule Używanie intencji do wyświetlania danych z kalendarza.
Wyświetl zdarzenie wskazane przez zasadę <event_id>. CalendarContract.EXTRA_EVENT_BEGIN_TIME


CalendarContract.EXTRA_EVENT_END_TIME
EDIT

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

Możesz też odwołać się do identyfikatora URI za pomocą Events.CONTENT_URI Przykład korzystania z tej intencji znajdziesz w artykule Korzystanie z intencji do edytowania zdarzenia.
Edytuj zdarzenie określone przez funkcję <event_id>. CalendarContract.EXTRA_EVENT_BEGIN_TIME


CalendarContract.EXTRA_EVENT_END_TIME
EDIT

INSERT

content://com.android.calendar/events

Możesz też użyć URI z Events.CONTENT_URI. Przykład korzystania z tej intencji znajdziesz w artykule Korzystanie z intencji do wstawiania zdarzenia.
Utwórz wydarzenie. wszelkie dodatki wymienione w tabeli poniżej.

Tabela poniżej zawiera listę dodatkowych informacji o intencji obsługiwanych przez dostawcę kalendarza:

Dodatkowa intencja Opis
Events.TITLE Nazwa zdarzenia.
CalendarContract.EXTRA_EVENT_BEGIN_TIME Czas rozpoczęcia zdarzenia w milisekundach od początku epoki.
CalendarContract.EXTRA_EVENT_END_TIME Czas zakończenia zdarzenia w milisekundach od początku epoki.
CalendarContract.EXTRA_EVENT_ALL_DAY Wartość logiczna wskazująca, że wydarzenie trwa cały dzień. Wartość może być true lub false.
Events.EVENT_LOCATION Lokalizacja zdarzenia.
Events.DESCRIPTION Opis zdarzenia.
Intent.EXTRA_EMAIL Adresy e-mail osób, które chcesz zaprosić, jako listy rozdzielonej przecinkami.
Events.RRULE Reguła powtarzania zdarzenia.
Events.ACCESS_LEVEL Określa, czy wydarzenie jest prywatne czy publiczne.
Events.AVAILABILITY Jeśli wydarzenie jest zaliczane do czasu dużego ruchu lub jest wolne od pracy, można je zaplanować.

W sekcjach poniżej znajdziesz informacje o sposobach korzystania z tych intencji.

Użyj intencji do wstawienia zdarzenia

Użycie okna dialogowego INSERT pozwala aplikacji przekazać zadanie wstawiania wydarzenia do Kalendarza. Dzięki temu plik manifestu nie musi już zawierać uprawnienia WRITE_CALENDAR.

Gdy użytkownicy uruchamiają aplikację, która korzysta z tego podejścia, aplikacja przekierowuje ich do Kalendarza, aby mogli dokończyć dodawanie wydarzenia. Intencje INSERT używają dodatkowych pól, aby wstępnie wypełnić formularz szczegółami wydarzenia w Kalendarzu. Użytkownicy mogą anulować wydarzenie, edytować formularz w razie potrzeby lub zapisać wydarzenie w swoich kalendarzach.

Oto fragment kodu, który planuje zdarzenie na 19 stycznia 2012 r., które będzie trwać od 7:30 do 8:30. Pamiętaj o tych informacjach dotyczących tego fragmentu kodu:

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

Edytowanie zdarzenia za pomocą intencji

Możesz zaktualizować zdarzenie bezpośrednio, zgodnie z opisem w sekcji Aktualizowanie zdarzeń. Jednak użycie intencji EDIT pozwala aplikacji, która nie ma uprawnień, przekazać edycję wydarzenia aplikacji Kalendarz. Gdy użytkownicy skończą edytowanie wydarzenia w Kalendarzu, wrócą do pierwotnej aplikacji.

Oto przykład intencji, która ustawia nowy tytuł określonego wydarzenia i pozwala użytkownikom edytować to wydarzenie w Kalendarzu.

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

Wyświetlanie danych z kalendarza za pomocą intencji

Dostawca Kalendarza udostępnia dwa sposoby korzystania z intencji VIEW:

  • Aby otworzyć Kalendarz w określonym dniu.
  • Wyświetlanie wydarzenia.

Ten przykład pokazuje, jak otworzyć Kalendarz w określonym dniu:

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

Oto przykład, jak otworzyć zdarzenie do wyświetlenia:

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

Adaptery synchronizacji

Różnice w dostępie aplikacji i adaptera synchronizacji do dostawcy kalendarza są niewielkie:

  • Adapter synchronizacji musi wskazywać, że jest adapterem synchronizacji, przez ustawienie wartości CALLER_IS_SYNCADAPTER na true.
  • Adapter synchronizacji musi udostępniać w identyfikatorze URI parametry ACCOUNT_NAME i ACCOUNT_TYPE jako parametry zapytania.
  • Adapter synchronizacji ma dostęp do zapisu w większej liczbie kolumn niż aplikacja lub widżet. Na przykład aplikacja może modyfikować tylko kilka cech kalendarza, takie jak nazwa, wyświetlana nazwa, ustawienie widoczności i to, czy kalendarz zsynchronizowano. Dla porównania adapter synchronizacji ma dostęp nie tylko do tych kolumn, ale także do wielu innych, takie jak kolor kalendarza, strefa czasowa, poziom dostępu, lokalizacja itd. Adapter synchronizacji jest jednak ograniczony do ACCOUNT_NAME oraz ACCOUNT_TYPE.

Oto pomocnicza metoda, która zwraca identyfikator URI do użycia z adapterem synchronizacji:

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