Penyedia Kalender adalah repositori untuk acara kalender pengguna. Tujuan Calendar Provider API memungkinkan Anda melakukan kueri, menyisipkan, memperbarui, dan menghapus pada kalender, acara, peserta, pengingat, dan sebagainya.
Calender Provider API bisa digunakan oleh aplikasi dan adaptor sinkronisasi. Aturannya bervariasi bergantung pada jenis program yang melakukan panggilan. Dokumen ini berfokus terutama pada penggunaan Calendar Provider API sebagai aplikasi. Sebagai diskusi tentang perbedaan adaptor sinkronisasi, lihat Adaptor Sinkronisasi.
Biasanya, untuk membaca atau menulis data kalender, manifes aplikasi harus berisi izin yang sesuai, yang dijelaskan dalam Izin Pengguna. Untuk mempermudah melakukan operasi umum, Kalender Penyedia menawarkan serangkaian intent, seperti yang dijelaskan dalam Kalender Intent. Semua intent ini membawa pengguna ke aplikasi Kalender untuk menyisipkan, melihat, dan mengedit acara. Pengguna berinteraksi dengan aplikasi Kalender, lalu kembali ke aplikasi semula. Jadi, aplikasi Anda tidak perlu meminta izin, juga tidak perlu menyediakan antarmuka pengguna untuk melihat atau membuat peristiwa.
Dasar-dasar
Penyedia konten menyimpan data dan membuatnya dapat diakses oleh aplikasi. Penyedia konten yang ditawarkan oleh platform Android (termasuk Penyedia Kalender) biasanya mengekspos data sebagai satu set tabel berdasarkan sebuah model {i>database <i}relasional, di mana setiap baris adalah {i>record<i} dan setiap kolom adalah data jenis dan makna tertentu. Melalui Calendar Provider API, aplikasi dan adaptor sinkronisasi bisa mendapatkan akses baca/tulis ke tabel {i>database<i} yang menyimpan data kalender pengguna.
Setiap penyedia konten mengekspos URI publik (yang digabungkan sebagai
Uri
) yang mengidentifikasi set datanya secara unik. Penyedia konten yang mengontrol beberapa set data (beberapa tabel) mengekspos URI terpisah untuk tiap set. Semua
URI untuk penyedia diawali dengan string "content://". Ini
mengidentifikasi bahwa data dikontrol oleh penyedia konten. Kalender
Penyedia menentukan konstanta untuk URI bagi setiap class (tabel). URI
ini memiliki format <class>.CONTENT_URI
. Sebagai
contoh, Events.CONTENT_URI
.
Gambar 1 menampilkan representasi grafis model data Penyedia Kalender. Ini menunjukkan tabel-tabel utama dan isian yang menghubungkan mereka satu sama lain.
Seorang pengguna bisa memiliki beberapa kalender, dan kalender yang berbeda bisa dikaitkan dengan tipe akun yang berbeda (Google Kalender, Exchange, dan seterusnya).
CalendarContract
menentukan model data informasi yang terkait dengan kalender dan acara. Data ini disimpan di sejumlah tabel, yang dicantumkan di bawah ini.
Tabel (Kelas) | Deskripsi |
---|---|
Tabel ini menyimpan informasi khusus kalender. Setiap baris dalam tabel ini berisi detail untuk satu kalender, seperti nama, warna, informasi sinkronisasi, dan sebagainya. | |
CalendarContract.Events |
Tabel ini menyimpan
informasi khusus peristiwa. Setiap baris dalam tabel ini berisi informasi untuk satu peristiwa, misalnya judul peristiwa, lokasi, waktu mulai, waktu berakhir, dan sebagainya. Kejadian bisa terjadi satu kali atau bisa berulang beberapa kali. Peserta, pengingat, dan properti perluasan disimpan dalam tabel terpisah.
Masing-masing memiliki EVENT_ID
yang merujuk _ID dalam tabel Peristiwa. |
CalendarContract.Instances |
Tabel ini menyimpan waktu mulai dan waktu berakhir untuk setiap kejadian. Setiap baris dalam tabel ini mewakili satu kejadian. Untuk peristiwa satu kali, ada pemetaan 1:1 antara instance dan peristiwa. Untuk acara berulang, beberapa baris akan otomatis yang terkait dengan beberapa kejadian itu. |
CalendarContract.Attendees |
Tabel ini menyimpan informasi peserta (tamu) acara. Setiap baris mewakili satu tamu dari peristiwa. Ini menentukan jenis tamu dan respons kehadiran tamu untuk acara. |
CalendarContract.Reminders |
Tabel ini menyimpan
data pemberitahuan/peringatan. Tiap baris mewakili satu peringatan untuk sebuah kejadian. Channel
acara bisa memiliki beberapa pengingat. Jumlah maksimum pengingat per acara adalah
ditentukan dalam
Halo MAX_REMINDERS ,
yang diatur oleh adaptor sinkronisasi yang
yang memiliki kalender yang ditentukan. Pengingat ditetapkan dalam menit sebelum peristiwa
dan memiliki metode yang menentukan cara pengguna akan diperingatkan. |
Calendar Provider API didesain agar luwes dan tangguh. Sementara itu, Anda perlu memberikan pengalaman pengguna akhir yang baik dan melindungi integritas kalender dan datanya. Untuk mencapainya, berikut beberapa hal yang perlu diingat saat menggunakan API ini:
- Menyisipkan, memperbarui, dan melihat acara kalender. Untuk menyisipkan, mengubah, dan membaca peristiwa secara langsung dari Penyedia Kalender, Anda memerlukan izin yang sesuai. Namun, jika Anda tidak sedang membangun aplikasi atau adaptor sinkronisasi kalender berfitur lengkap, maka tidak perlu meminta izin. Sebagai gantinya, Anda bisa menggunakan intent yang didukung oleh aplikasi Kalender Android untuk menyerahkan operasi baca dan tulis ke aplikasi itu. Saat Anda menggunakan intent, aplikasi Anda akan mengirim pengguna ke aplikasi Kalender untuk melakukan operasi yang diinginkan dalam formulir yang sudah diisi. Setelah selesai, formulir tersebut dikembalikan ke aplikasi Anda. Dengan merancang aplikasi Anda untuk melakukan operasi umum melalui Kalender, Anda memberikan antarmuka pengguna yang konsisten dan kuat kepada pengguna. Ini adalah pendekatan yang disarankan. Untuk informasi selengkapnya, lihat Kalender Intent.
- Adaptor sinkronisasi. {i>Sync adaptor<i} menyinkronkan data kalender
pada perangkat pengguna dengan server atau sumber data lain. Dalam
tabel
CalendarContract.Calendars
danCalendarContract.Events
, ada kolom yang dicadangkan untuk digunakan adaptor sinkronisasi. Penyedia dan aplikasi tidak boleh memodifikasinya. Bahkan, mereka tidak terlihat kecuali jika diakses sebagai adaptor sinkronisasi. Untuk informasi selengkapnya tentang adaptor sinkronisasi, lihat Adaptor Sinkronisasi.
Izin pengguna
Untuk membaca data kalender, aplikasi harus menyertakan izin READ_CALENDAR
dalam file manifesnya. Ini
harus menyertakan izin WRITE_CALENDAR
untuk menghapus, menyisipkan, atau memperbarui data kalender:
<?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>
Tabel kalender
Tabel CalendarContract.Calendars
berisi detail
untuk setiap kalender. Hal berikut
Kolom kalender dapat ditulis oleh aplikasi dan adaptor sinkronisasi.
Untuk mengetahui daftar lengkap kolom yang didukung, lihat
Referensi CalendarContract.Calendars
.
Konstanta | Deskripsi |
---|---|
NAME |
Nama kalender. |
CALENDAR_DISPLAY_NAME |
Nama kalender ini yang ditampilkan kepada pengguna. |
VISIBLE |
Sebuah boolean yang menunjukkan apakah kalender dipilih untuk ditampilkan. Nilai
0 menunjukkan bahwa acara yang terkait dengan kalender ini tidak boleh
ditampilkan. Nilai 1 menunjukkan bahwa peristiwa yang terkait dengan kalender ini harus
ditampilkan. Nilai ini memengaruhi pembuatan baris dalam tabel CalendarContract.Instances . |
SYNC_EVENTS |
Boolean yang menunjukkan apakah kalender harus disinkronkan dan memiliki yang disimpan di perangkat. Nilai 0 berarti jangan sinkronkan kalender ini atau menyimpan kejadiannya di perangkat. Nilai 1 berarti menyinkronkan peristiwa untuk kalender ini dan menyimpan peristiwanya di perangkat. |
Menyertakan tipe akun untuk semua operasi
Jika Anda membuat kueri pada Calendars.ACCOUNT_NAME
, Anda juga harus menyertakan
Calendars.ACCOUNT_TYPE
dalam pilihan. Hal itu karena akun tertentu
hanya dianggap unik mengingat ACCOUNT_NAME
dan
ACCOUNT_TYPE
. ACCOUNT_TYPE
adalah string yang sesuai dengan
pengautentikasi akun yang digunakan saat akun didaftarkan dengan
AccountManager
. Ada juga jenis akun khusus
memanggil ACCOUNT_TYPE_LOCAL
untuk
kalender yang tidak terkait dengan akun perangkat.
ACCOUNT_TYPE_LOCAL
akun tidak mendapatkan
disinkronkan.
Membuat kueri kalender
Berikut adalah contoh yang menunjukkan cara mendapatkan kalender yang dimiliki oleh pengguna
tertentu. Untuk memudahkan, dalam contoh ini, operasi kueri ditampilkan dalam
thread antarmuka pengguna ("thread utama"). Dalam praktiknya, hal ini harus dilakukan dalam thread
asinkron, bukan di thread utama. Untuk pembahasan lebih lanjut, lihat
Loader. Jika Anda tidak hanya
membaca data tetapi mengubahnya, lihat 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;
Di bagian berikutnya pada contoh ini, Anda akan melakukan kueri. Pilihan
menentukan kriteria kueri. Dalam contoh ini, kueri mencari
kalender yang memiliki ACCOUNT_NAME
"hera@example.com", ACCOUNT_TYPE
"com.example", dan OWNER_ACCOUNT
"hera@example.com". Jika Anda ingin melihat semua kalender yang
telah dilihat, bukan hanya kalender yang dimiliki pengguna, hapus OWNER_ACCOUNT
.
Kueri menampilkan Cursor
yang dapat Anda gunakan untuk menelusuri set hasil yang ditampilkan oleh database
kueri. Untuk diskusi selengkapnya tentang penggunaan kueri dalam penyedia konten,
lihat Penyedia Konten.
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);
Bagian berikutnya ini menggunakan kursor untuk merunut set hasil. Bagian ini menggunakan konstanta yang disiapkan di awal contoh untuk menampilkan nilai untuk setiap kolom.
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... ... }
Memodifikasi kalender
Untuk memperbarui kalender, Anda dapat memberikan _ID
kalender tersebut sebagai ID yang ditambahkan ke
URI
withAppendedId()
atau sebagai item pilihan pertama. Pilihan
harus diawali dengan "_id=?"
, dan karakter
selectionArg
harus berupa _ID
kalender.
Anda juga bisa melakukan pembaruan dengan mengkodekan ID dalam URI. Contoh ini mengubah
nama tampilan kalender menggunakan
pendekatan
(withAppendedId()
):
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);
Menyisipkan kalender
Kalender didesain untuk dikelola terutama oleh adaptor sinkronisasi, sehingga Anda
hanya boleh menyisipkan kalender baru sebagai adaptor sinkronisasi. Sebagian besar,
aplikasi hanya dapat membuat perubahan semu pada kalender, seperti mengubah nama tampilan. Jika
aplikasi perlu membuat kalender lokal, aplikasi
dapat melakukannya dengan menjalankan
penyisipan kalender sebagai adaptor sinkronisasi, menggunakan ACCOUNT_TYPE
dari ACCOUNT_TYPE_LOCAL
.
ACCOUNT_TYPE_LOCAL
adalah jenis akun khusus untuk kalender yang tidak
terkait dengan akun perangkat. Kalender tipe ini tidak disinkronkan dengan server. Untuk
diskusi tentang adaptor sinkronisasi, lihat Adaptor Sinkronisasi.
Tabel Events
Tabel CalendarContract.Events
berisi detail
untuk setiap peristiwa. Untuk menambah, memperbarui, atau menghapus peristiwa, aplikasi harus
menyertakan izin WRITE_CALENDAR
dalam
file manifes.
Kolom Events berikut ini dapat ditulis oleh aplikasi dan adaptor
sinkronisasi. Untuk mengetahui daftar lengkap kolom yang didukung, lihat referensi CalendarContract.Events
.
Konstanta | Deskripsi |
---|---|
CALENDAR_ID |
_ID kalender yang memiliki acara tersebut. |
ORGANIZER |
Email penyelenggara (pemilik) kejadian. |
TITLE |
Judul kejadian. |
EVENT_LOCATION |
Tempat kejadian. |
DESCRIPTION |
Keterangan kejadian. |
DTSTART |
Waktu mulai kejadian dalam milidetik UTC sejak waktu patokan. |
DTEND |
Waktu selesai kejadian dalam milidetik UTC sejak waktu patokan. |
EVENT_TIMEZONE |
Zona waktu kejadian. |
EVENT_END_TIMEZONE |
Zona waktu untuk waktu selesai kejadian. |
DURATION |
Durasi peristiwa dalam format RFC5545.
Misalnya, nilai "PT1H" menyatakan bahwa peristiwa
akan berlangsung selama satu jam, dan nilai "P2W" menunjukkan
dengan durasi 2 minggu. |
ALL_DAY |
Nilai 1 menunjukkan bahwa peristiwa ini berlangsung sepanjang hari, seperti yang ditetapkan oleh zona waktu lokal. Nilai 0 menunjukkan bahwa kejadian ini adalah kejadian biasa yang mungkin dimulai dan berakhir kapan saja sepanjang hari. |
RRULE |
Aturan perulangan untuk format kejadian. Misalnya,
"FREQ=WEEKLY;COUNT=10;WKST=SU" . Anda dapat menemukan
contoh lainnya di sini. |
RDATE |
Tanggal perulangan kejadian.
Anda biasanya menggunakan RDATE
bersama dengan RRULE
untuk menentukan
kumpulan data gabungan
pengulangan yang
berulang. Untuk diskusi selengkapnya, lihat spesifikasi RFC5545. |
AVAILABILITY |
Jika peristiwa ini dihitung sebagai waktu sibuk atau waktu luang yang dapat dijadwalkan. |
GUESTS_CAN_MODIFY |
Apakah tamu bisa memodifikasi kejadian atau tidak. |
GUESTS_CAN_INVITE_OTHERS |
Apakah tamu bisa mengundang tamu lain atau tidak. |
GUESTS_CAN_SEE_GUESTS |
Apakah tamu bisa membaca daftar peserta atau tidak. |
Tambahkan kejadian
Saat aplikasi Anda menyisipkan peristiwa baru, sebaiknya gunakan
Intent INSERT
, seperti yang dijelaskan dalam Menggunakan intent untuk menyisipkan peristiwa. Namun, jika Anda
diperlukan, Anda dapat memasukkan
peristiwa secara langsung. Bagian ini menjelaskan cara melakukan
ini.
Berikut ini adalah aturan untuk menyisipkan kejadian baru:
- Anda harus menyertakan
CALENDAR_ID
danDTSTART
. - Anda harus menyertakan
EVENT_TIMEZONE
. Untuk mendapatkan daftar ID zona waktu yang diinstal sistem, gunakangetAvailableIDs()
. Perhatikan bahwa aturan ini tidak berlaku jika Anda menyisipkan peristiwa melalui IntentINSERT
, yang dijelaskan dalam Menggunakan intent untuk menyisipkan peristiwa—dalam skenario tersebut, zona waktu default akan disediakan. - Untuk acara tidak berulang, Anda harus menyertakan
DTEND
. - Untuk peristiwa berulang, Anda harus menyertakan
DURATION
selainRRULE
atauRDATE
. Perhatikan bahwa aturan ini tidak berlaku jika Anda menyisipkan peristiwa melalui IntentINSERT
, yang dijelaskan di Menggunakan intent untuk menyisipkan peristiwa—dalam Anda dapat menggunakanRRULE
bersama denganDTSTART
danDTEND
, serta aplikasi Kalender akan mengonversinya menjadi durasi secara otomatis.
Berikut ini adalah contoh penyisipan kejadian. Hal ini dilakukan di UI
agar lebih mudah. Dalam praktiknya, penyisipan dan pembaruan harus dilakukan dalam
thread asinkron untuk memindahkan tindakan ke thread latar belakang. Untuk selengkapnya
informasi tambahan, lihat 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 // //
Catatan: Lihat cara contoh ini merekam peristiwa setelah peristiwa dibuat. Inilah cara termudah untuk mendapatkan ID kejadian. Anda sering kali memerlukan ID acara untuk melakukan operasi kalender lainnya—misalnya, untuk menambahkan peserta atau pengingat ke acara.
Peristiwa update
Jika aplikasi Anda ingin mengizinkan pengguna mengedit peristiwa, sebaiknya
gunakan Intent EDIT
, seperti
dijelaskan dalam Menggunakan intent untuk mengedit peristiwa.
Akan tetapi, jika perlu, Anda bisa menyisipkan kejadian secara langsung. Untuk melakukan pembaruan
Peristiwa, Anda dapat memberikan _ID
peristiwa sebagai ID yang ditambahkan ke URI (withAppendedId()
)
atau sebagai item pilihan pertama.
Pemilihan harus dimulai dengan "_id=?"
, dan selectionArg
pertama harus berupa _ID
peristiwa. Anda juga dapat melakukan pembaruan dengan menggunakan pemilihan tanpa ID. Berikut adalah contoh pembaruan
peristiwa. Perintah ini mengubah judul acara dengan menggunakan
withAppendedId()
pendekatan:
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);
Hapus acara
Anda dapat menghapus peristiwa dengan _ID
sebagai ID yang ditambahkan pada URI, atau dengan menggunakan
pemilihan standar. Jika Anda menggunakan ID yang ditambahkan, Anda juga tidak dapat melakukan pemilihan.
Ada dua versi penghapusan: sebagai aplikasi dan adaptor sinkronisasi. Penghapusan
aplikasi menetapkan kolom deleted ke 1. Penanda ini memberi tahu
{i>synchronize<i} bahwa baris telah
dihapus dan bahwa penghapusan ini harus
yang disebarkan ke server. Penghapusan adaptor sinkronisasi akan menghapus kejadian dari
{i>database<i} beserta semua data yang terkait. Berikut ini contoh aplikasi
menghapus peristiwa melalui _ID
-nya:
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);
Tabel peserta
Setiap baris pada tabel CalendarContract.Attendees
mewakili satu peserta atau
tamu dari suatu acara. Memanggil
query()
akan menampilkan daftar peserta untuk
peristiwa dengan EVENT_ID
yang diberikan.
EVENT_ID
ini
harus cocok dengan _ID
peristiwa tertentu.
Tabel berikut mencantumkan
bidang yang dapat ditulis. Saat memasukkan peserta baru, Anda harus menyertakan semuanya
kecuali ATTENDEE_NAME
.
Konstanta | Deskripsi |
---|---|
EVENT_ID |
ID kejadian. |
ATTENDEE_NAME |
Nama peserta. |
ATTENDEE_EMAIL |
Alamat email peserta. |
ATTENDEE_RELATIONSHIP |
Hubungan peserta dengan kejadian. Salah satu dari: |
ATTENDEE_TYPE |
Tipe peserta. Salah satu dari: |
ATTENDEE_STATUS |
Status kehadiran peserta. Salah satu dari: |
Menambahkan peserta
Berikut ini adalah contoh yang menambahkan satu peserta ke kejadian. Perhatikan bahwa
EVENT_ID
wajib diisi:
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);
Tabel pengingat
Setiap baris pada tabel CalendarContract.Reminders
mewakili satu pengingat untuk suatu peristiwa. Menelepon
query()
menampilkan daftar pengingat untuk
peristiwa dengan nilai
EVENT_ID
.
Tabel berikut mencantumkan bidang-bidang yang bisa ditulis untuk pengingat. Semuanya harus
disertakan saat menyisipkan pengingat baru. Perhatikan bahwa adaptor sinkronisasi menetapkan atribut
jenis pengingat yang didukungnya dalam tabel CalendarContract.Calendars
. Lihat
ALLOWED_REMINDERS
untuk mengetahui detailnya.
Konstanta | Deskripsi |
---|---|
EVENT_ID |
ID kejadian. |
MINUTES |
Menit yang ditunggu untuk memicu kejadian pengingat. |
METHOD |
Metode alarm, seperti yang diatur pada server. Salah satu dari: |
Tambahkan pengingat
Contoh ini menambahkan pengingat ke kejadian. Pengingat terpicu 15 menit sebelum kejadian.
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);
Tabel instance
Tabel
CalendarContract.Instances
menyimpan
waktu mulai dan berakhir untuk kemunculan peristiwa. Setiap baris dalam tabel ini
mewakili satu kejadian. Tabel instance tidak dapat ditulis dan hanya menyediakan cara untuk membuat kueri kekerapan.
Tabel berikut mencantumkan beberapa kolom yang bisa Anda kueri untuk suatu instance. Perhatikan
bahwa zona waktu ditentukan oleh
KEY_TIMEZONE_TYPE
dan
KEY_TIMEZONE_INSTANCES
.
Konstanta | Deskripsi |
---|---|
BEGIN |
Waktu mulai instance, dalam milidetik UTC. |
END |
Waktu selesai instance, dalam milidetik UTC. |
END_DAY |
Hari berakhir Julian dari instance, relatif terhadap zona waktu Kalender. |
END_MINUTE |
Menit berakhir dari instance yang diukur dari tengah malam di zona waktu Kalender. |
EVENT_ID |
_ID peristiwa untuk instance ini. |
START_DAY |
Hari mulai Julian dari instance, relatif terhadap zona waktu Kalender. |
START_MINUTE |
Menit mulai instance yang diukur dari tengah malam, relatif terhadap Zona waktu kalender. |
Membuat kueri tabel Instance
Untuk melakukan kueri tabel Instances, Anda perlu menentukan rentang waktu kueri
dalam URI. Dalam contoh ini, CalendarContract.Instances
mendapatkan akses ke kolom TITLE
melalui
implementasi antarmuka CalendarContract.EventsColumns
.
Dengan kata lain, TITLE
ditampilkan melalui
tampilan database, bukan melalui kueri tabel CalendarContract.Instances
mentah.
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())); } }
Intent kalender
Aplikasi Anda tidak memerlukan izin untuk membaca dan menulis data kalender. Sebagai gantinya, aplikasi bisa menggunakan intent yang didukung oleh aplikasi Kalender Android untuk menyerahkan operasi baca dan tulis ke aplikasi tersebut. Tabel berikut mencantumkan maksud yang didukung oleh Penyedia Kalender:
Tindakan | URI | Deskripsi | Konten bonus |
---|---|---|---|
VIEW |
CalendarContract.CONTENT_URI .
Untuk contoh penggunaan intent ini, lihat Menggunakan intent untuk menampilkan data kalender.
|
Membuka kalender pada waktu yang ditentukan oleh <ms_since_epoch> . |
Tidak ada. |
Events.CONTENT_URI .
Untuk contoh penggunaan intent ini, lihat Menggunakan intent untuk melihat data kalender.
|
Melihat peristiwa yang ditentukan oleh <event_id> . |
CalendarContract.EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_END_TIME |
|
EDIT |
Events.CONTENT_URI .
Untuk contoh penggunaan intent ini, lihat Menggunakan intent untuk mengedit peristiwa.
|
Mengedit peristiwa yang ditentukan oleh <event_id> . |
CalendarContract.EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_END_TIME |
EDIT INSERT |
Events.CONTENT_URI .
Untuk contoh penggunaan intent ini, lihat Menggunakan intent untuk menyisipkan peristiwa.
|
Buat acara. | Ekstra apa saja yang tercantum dalam tabel di bawah. |
Tabel berikut mencantumkan tambahan maksud yang didukung oleh Penyedia Kalender:
Ekstra Maksud | Deskripsi |
---|---|
Events.TITLE |
Nama kejadian. |
CalendarContract.EXTRA_EVENT_BEGIN_TIME |
Waktu mulai kejadian dalam milidetik sejak waktu patokan. |
CalendarContract.EXTRA_EVENT_END_TIME |
Waktu selesai kejadian dalam milidetik sejak waktu patokan. |
CalendarContract.EXTRA_EVENT_ALL_DAY |
Sebuah boolean yang menunjukkan bahwa kejadian sehari penuh. Nilainya dapat berupa
true atau false . |
Events.EVENT_LOCATION |
Lokasi kejadian. |
Events.DESCRIPTION |
Keterangan kejadian. |
Intent.EXTRA_EMAIL |
Alamat email mereka yang harus diundang berupa daftar yang dipisahkan koma. |
Events.RRULE |
Aturan perulangan kejadian. |
Events.ACCESS_LEVEL |
Apakah kejadian bersifat privat atau publik. |
Events.AVAILABILITY |
Jika kejadian ini dihitung sebagai waktu sibuk atau waktu bebas yang bisa dijadwalkan. |
Bagian berikut menjelaskan cara menggunakan semua intent ini.
Menggunakan intent untuk menyisipkan kejadian
Penggunaan Intent INSERT
memungkinkan aplikasi Anda menyerahkan tugas penyisipan acara ke Kalender itu sendiri.
Dengan pendekatan ini, aplikasi Anda bahkan tidak perlu menyertakan izin WRITE_CALENDAR
dalam file manifes-nya.
Saat pengguna menjalankan aplikasi yang menggunakan pendekatan ini, aplikasi akan mengirim
izin ke Kalender untuk menyelesaikan penambahan peristiwa. Intent INSERT
menggunakan kolom tambahan untuk
mengisi otomatis formulir dengan detail acara di Kalender. Pengguna kemudian dapat
membatalkan acara, mengedit formulir sesuai kebutuhan, atau menyimpan acara ke
kalender mereka.
Berikut ini cuplikan kode yang menjadwalkan peristiwa pada tanggal 19 Januari 2012, yang menjalankan dari pukul 07.30 hingga 08.30. Perhatikan hal-hal berikut tentang cuplikan kode ini:
- Cuplikan kode ini menetapkan
Events.CONTENT_URI
sebagai Uri. - Cuplikan kode ini menggunakan kolom tambahan
CalendarContract.EXTRA_EVENT_BEGIN_TIME
danCalendarContract.EXTRA_EVENT_END_TIME
untuk mengisi otomatis formulir dengan waktu peristiwa. Nilai untuk waktu ini harus dalam milidetik UTC dari epoch. - Cuplikan kode ini menggunakan kolom ekstra
Intent.EXTRA_EMAIL
untuk memberikan daftar undangan yang dipisahkan koma, yang ditetapkan melalui alamat email.
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);
Menggunakan intent untuk mengedit kejadian
Anda dapat memperbarui peristiwa secara langsung, seperti yang dijelaskan dalam Memperbarui peristiwa. Namun, penggunaan Intent EDIT
memungkinkan aplikasi yang
tidak memiliki izin untuk menyerahkan pengeditan acara ke aplikasi Kalender.
Setelah pengguna selesai mengedit acara di Kalender, mereka akan dikembalikan ke
aplikasi asli.
Berikut contoh intent yang menetapkan judul acara tertentu dan memungkinkan pengguna mengedit acara dalam Kalender.
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);
Menggunakan intent untuk menampilkan data kalender
Penyedia Kalender menyediakan dua cara menggunakan Intent VIEW
:
- Untuk membuka Kalender pada tanggal tertentu.
- Untuk menampilkan sebuah kejadian.
Berikut ini adalah contoh yang menampilkan cara membuka Kalender pada tanggal tertentu:
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);
Berikut ini adalah contoh yang menampilkan cara membuka kejadian untuk menampilkan:
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);
Adaptor sinkronisasi
Hanya ada perbedaan kecil dalam cara aplikasi dan adaptor sinkronisasi mengakses Penyedia Kalender:
- Adaptor sinkronisasi perlu menentukan bahwa dirinya adalah adaptor sinkronisasi dengan menetapkan
CALLER_IS_SYNCADAPTER
ketrue
. - Adaptor sinkronisasi perlu menyediakan
ACCOUNT_NAME
danACCOUNT_TYPE
sebagai parameter kueri dalam URI. - Adaptor sinkronisasi memiliki akses tulis ke lebih banyak kolom daripada aplikasi atau widget.
Misalnya, aplikasi hanya dapat mengubah beberapa karakteristik kalender,
seperti nama, nama tampilan, setelan visibilitas, dan apakah kalender
disinkronkan atau tidak. Sebagai perbandingan, adaptor sinkronisasi bisa mengakses bukan hanya kolom-kolom itu, tetapi banyak kolom lainnya,
seperti warna kalender, zona waktu, tingkat akses, lokasi, dan sebagainya.
Namun, adaptor sinkronisasi dibatasi pada
ACCOUNT_NAME
danACCOUNT_TYPE
yang ditentukannya.
Berikut ini adalah metode pembantu yang bisa Anda gunakan untuk mengembalikan URI bagi penggunaan dengan adaptor sinkronisasi:
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(); }