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ą.
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 |
---|---|
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
iCalendarContract.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_LOCAL
to 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 INSERT
intencji, 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:
- Musisz uwzględnić
CALENDAR_ID
iDTSTART
. - Musisz uwzględnić
EVENT_TIMEZONE
. Aby uzyskać listę identyfikatorów strefy czasowej systemu, użyjgetAvailableIDs()
. Pamiętaj, że ta reguła nie ma zastosowania, jeśli wstawiasz zdarzenie za pomocą intencjiINSERT
opisanej w artykule Korzystanie z intencji do wstawienia zdarzenia w taki sposób, że: w tym scenariuszu zostanie podana domyślna strefa czasowa. - W przypadku wydarzeń niecyklicznych musisz dodać
DTEND
. - W przypadku wydarzeń cyklicznych oprócz
RRULE
lubRDATE
trzeba dodać elementDURATION
. Pamiętaj, że ta reguła nie ma zastosowania, jeśli wstawiasz zdarzenie za pomocą intencjiINSERT
opisanej w artykule Korzystanie z intencji do wstawienia zdarzenia w taki sposób, że: możesz używaćRRULE
w połączeniu z usługamiDTSTART
iDTEND
, a aplikacja Kalendarz automatycznie konwertuje go na czas trwania.
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 EDIT
intencji, 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_ID
musi 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 |
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. |
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 |
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 |
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:
- Określa
Events.CONTENT_URI
jak identyfikator URI. - Używa dodatkowych pól
CalendarContract.EXTRA_EVENT_BEGIN_TIME
iCalendarContract.EXTRA_EVENT_END_TIME
do wstępnego wypełnienia formularza z godziną zdarzenia. Wartości dla tych godzin muszą być podane w milisekundach UTC od początku epoki. - Używa on pola dodatkowego
Intent.EXTRA_EMAIL
do podania listy zaproszonych osób, określonych na podstawie adresu e-mail i rozdzielanych przecinkami.
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
natrue
. - Adapter synchronizacji musi udostępniać w identyfikatorze URI parametry
ACCOUNT_NAME
iACCOUNT_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
orazACCOUNT_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(); }