Ringkasan penyedia kalender

Penyedia Kalender adalah repositori untuk acara kalender pengguna. Calendar Provider API memungkinkan Anda melakukan operasi kueri, penyisipan, pembaruan, dan penghapusan pada hal-hal seperti kalender, acara, peserta, dan pengingat.

Calendar Provider API dapat digunakan oleh aplikasi dan adaptor sinkronisasi. Aturannya bervariasi, bergantung pada jenis program yang melakukan panggilan. Dokumen ini terutama berfokus pada penggunaan Calendar Provider API sebagai aplikasi. Untuk pembahasan tentang perbedaan adaptor sinkronisasi, lihat Adaptor Sinkronisasi.

Biasanya, untuk membaca atau menulis data kalender, manifes aplikasi harus menyertakan izin yang tepat, yang dijelaskan dalam Izin Pengguna. Untuk mempermudah pelaksanaan operasi umum, Penyedia Kalender menawarkan serangkaian intent, seperti yang dijelaskan dalam Intent Kalender. Intent ini mengarahkan pengguna ke aplikasi Kalender untuk menyisipkan, melihat, dan mengedit acara. Pengguna berinteraksi dengan aplikasi Kalender, lalu kembali ke aplikasi asli. Dengan demikian, aplikasi Anda tidak perlu meminta izin, juga tidak perlu menyediakan antarmuka pengguna untuk melihat atau membuat acara.

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 kumpulan tabel berdasarkan model database relasional, dengan setiap baris adalah kumpulan data dan setiap kolom adalah data dari jenis dan arti tertentu. Melalui Calendar Provider API, aplikasi dan adaptor sinkronisasi bisa mendapatkan akses baca/tulis ke tabel database yang menyimpan data kalender pengguna.

Setiap penyedia konten mengekspos URI publik (yang digabungkan sebagai objek Uri) yang mengidentifikasi set datanya secara unik. Penyedia konten yang mengontrol beberapa set data (beberapa tabel) mengekspos URI terpisah untuk setiap set data. Semua URI untuk penyedia dimulai dengan string "content://". Ini mengidentifikasi data sebagai data yang dikontrol oleh penyedia konten. Penyedia Kalender menentukan konstanta untuk URI untuk setiap class (tabel). URI ini memiliki format <class>.CONTENT_URI. Contohnya, Events.CONTENT_URI.

Gambar 1 menunjukkan representasi grafis model data Penyedia Kalender. Diagram ini menampilkan tabel utama dan kolom yang menghubungkannya satu sama lain.

Model Data Penyedia Kalender
Gambar 1. Model data Penyedia Kalender.

Pengguna dapat memiliki beberapa kalender, dan kalender yang berbeda dapat dikaitkan dengan jenis akun yang berbeda (Google Kalender, Exchange, dan sebagainya).

CalendarContract menentukan model data kalender dan informasi terkait acara. Data ini disimpan dalam sejumlah tabel, yang tercantum sebagai berikut.

Tabel (Class) Deskripsi

CalendarContract.Calendars

Tabel ini menyimpan informasi khusus kalender. Setiap baris dalam tabel ini berisi detail untuk satu kalender, seperti nama, warna, dan informasi sinkronisasi.
CalendarContract.Events Tabel ini menyimpan informasi khusus peristiwa. Setiap baris dalam tabel ini memiliki informasi untuk satu peristiwa—misalnya, judul acara, lokasi, waktu mulai, waktu berakhir. Acara dapat terjadi satu kali atau dapat berulang beberapa kali. Peserta, pengingat, dan properti tambahan disimpan dalam tabel terpisah. Masing-masing memiliki EVENT_ID yang merujuk ke _ID dalam tabel Events.
CalendarContract.Instances Tabel ini menyimpan waktu mulai dan berakhir untuk setiap kemunculan peristiwa. Setiap baris dalam tabel ini mewakili satu kemunculan peristiwa. Untuk acara satu kali, ada pemetaan 1:1 instance ke acara. Untuk acara berulang, beberapa baris akan otomatis dibuat sesuai dengan beberapa kemunculan acara tersebut.
CalendarContract.Attendees Tabel ini menyimpan informasi peserta (tamu) acara. Setiap baris mewakili satu tamu dari suatu acara. Ini menentukan jenis tamu dan respons kehadiran tamu untuk acara tersebut.
CalendarContract.Reminders Tabel ini menyimpan data pemberitahuan/notifikasi. Setiap baris mewakili satu pemberitahuan untuk suatu peristiwa. Acara dapat memiliki beberapa pengingat. Jumlah maksimum pengingat per acara ditentukan dalam MAX_REMINDERS, yang ditetapkan oleh adaptor sinkronisasi yang memiliki kalender tertentu. Pengingat ditentukan dalam menit sebelum acara dan memiliki metode yang menentukan cara pengguna akan diberi tahu.

Calendar Provider API dirancang agar fleksibel dan andal. Pada saat yang sama, penting untuk memberikan pengalaman pengguna akhir yang baik dan melindungi integritas kalender serta datanya. Untuk itu, berikut beberapa hal yang perlu diingat saat menggunakan API:

  • Menyisipkan, memperbarui, dan melihat acara kalender. Untuk menyisipkan, mengubah, dan membaca acara langsung dari Penyedia Kalender, Anda memerlukan izin yang sesuai. Namun, jika Anda tidak membuat aplikasi kalender atau adaptor sinkronisasi yang lengkap, Anda tidak perlu meminta izin ini. Sebagai gantinya, Anda dapat menggunakan intent yang didukung oleh aplikasi Kalender Android untuk menyerahkan operasi baca dan tulis ke aplikasi tersebut. Saat Anda menggunakan intent, aplikasi Anda akan mengarahkan pengguna ke aplikasi Kalender untuk melakukan operasi yang dipilih dalam formulir yang telah diisi otomatis. Setelah selesai, pengguna akan dikembalikan ke aplikasi Anda. Dengan mendesain aplikasi Anda untuk melakukan operasi umum melalui Kalender, Anda memberikan antarmuka pengguna yang konsisten dan andal kepada pengguna. Ini adalah pendekatan yang direkomendasikan. Untuk informasi selengkapnya, lihat Intent Kalender.
  • Adaptor sinkronisasi. Adaptor sinkronisasi menyinkronkan data kalender di perangkat pengguna dengan server atau sumber data lain. Dalam tabel CalendarContract.Calendars dan CalendarContract.Events, ada kolom yang dicadangkan untuk digunakan oleh adaptor sinkronisasi. Penyedia dan aplikasi tidak boleh mengubahnya. Bahkan, penyedia ini tidak terlihat kecuali jika diakses sebagai adaptor sinkronisasi. Untuk mengetahui informasi selengkapnya tentang adaptor sinkronisasi, lihat Adaptor Sinkronisasi.

Izin pengguna

Untuk membaca data kalender, aplikasi harus menyertakan izin READ_CALENDAR dalam file manifesnya. Izin 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. Kolom Kalender berikut 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 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 acara 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 acaranya disimpan di perangkat. Nilai 0 berarti jangan sinkronkan kalender ini atau simpan acaranya di perangkat. Nilai 1 berarti menyinkronkan acara untuk kalender ini dan menyimpan acaranya di perangkat.

Menyertakan jenis akun untuk semua operasi

Jika membuat kueri pada Calendars.ACCOUNT_NAME, Anda juga harus menyertakan Calendars.ACCOUNT_TYPE dalam pilihan. Hal ini karena akun tertentu hanya dianggap unik jika memiliki 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 yang disebut ACCOUNT_TYPE_LOCAL untuk kalender yang tidak terkait dengan akun perangkat. Akun ACCOUNT_TYPE_LOCAL tidak disinkronkan.

Membuat kueri kalender

Berikut adalah contoh yang menunjukkan cara mendapatkan kalender yang dimiliki oleh pengguna tertentu. Agar lebih mudah, dalam contoh ini operasi kueri ditampilkan di thread antarmuka pengguna ("thread utama"). Dalam praktiknya, hal ini harus dilakukan di thread asinkron, bukan di thread utama. Untuk pembahasan lebih lanjut, lihat Loader. Jika Anda tidak hanya membaca data, tetapi juga 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 contoh berikutnya, Anda akan membuat kueri. Pemilihan menentukan kriteria untuk 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 pengguna, bukan hanya kalender yang dimiliki pengguna, hapus OWNER_ACCOUNT. Kueri menampilkan objek Cursor yang dapat Anda gunakan untuk melintasi set hasil yang ditampilkan oleh kueri database. Untuk pembahasan lebih lanjut tentang penggunaan kueri di 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 menggunakan kursor untuk menelusuri set hasil. Fungsi ini menggunakan konstanta yang disiapkan di awal contoh untuk menampilkan nilai 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...

   ...
}

Mengubah kalender

Untuk melakukan update kalender, Anda dapat memberikan _ID kalender sebagai ID yang ditambahkan ke Uri (withAppendedId()) atau sebagai item pilihan pertama. Pilihan harus dimulai dengan "_id=?", dan selectionArg pertama harus berupa _ID kalender. Anda juga dapat melakukan update dengan mengenkode ID di 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, jadi Anda hanya boleh menyisipkan kalender baru sebagai adaptor sinkronisasi. Sebagian besar, aplikasi hanya dapat membuat perubahan kecil pada kalender, seperti mengubah nama tampilan. Jika aplikasi perlu membuat kalender lokal, aplikasi dapat melakukannya dengan melakukan 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 jenis ini tidak disinkronkan ke server. Untuk pembahasan tentang adaptor sinkronisasi, lihat Adaptor Sinkronisasi.

Tabel peristiwa

Tabel CalendarContract.Events berisi detail untuk setiap peristiwa. Untuk menambahkan, memperbarui, atau menghapus acara, aplikasi harus menyertakan izin WRITE_CALENDAR dalam file manifesnya.

Kolom Peristiwa berikut 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 berisi acara.
ORGANIZER Email penyelenggara (pemilik) acara.
TITLE Judul acara.
EVENT_LOCATION Tempat acara berlangsung.
DESCRIPTION Deskripsi peristiwa.
DTSTART Waktu acara dimulai dalam milidetik UTC sejak epoch.
DTEND Waktu berakhirnya acara dalam milidetik UTC sejak epoch.
EVENT_TIMEZONE Zona waktu untuk acara.
EVENT_END_TIMEZONE Zona waktu untuk waktu berakhir acara.
DURATION Durasi acara dalam format RFC5545. Misalnya, nilai "PT1H" menyatakan bahwa acara harus berlangsung selama satu jam, dan nilai "P2W" menunjukkan durasi 2 minggu.
ALL_DAY Nilai 1 menunjukkan bahwa acara ini berlangsung sepanjang hari, seperti yang ditentukan oleh zona waktu lokal. Nilai 0 menunjukkan bahwa acara tersebut adalah acara reguler yang dapat dimulai dan berakhir kapan saja dalam sehari.
RRULE Aturan pengulangan untuk format acara. Contoh, "FREQ=WEEKLY;COUNT=10;WKST=SU" Untuk contoh lainnya, lihat spesifikasi RFC5545.
RDATE Tanggal pengulangan acara. Anda biasanya menggunakan RDATE bersama dengan RRULE untuk menentukan kumpulan agregat kemunculan berulang. Untuk diskusi lebih lanjut, lihat spesifikasi RFC5545.
AVAILABILITY Apakah acara ini dihitung sebagai waktu sibuk atau waktu luang yang dapat dijadwalkan ulang.
GUESTS_CAN_MODIFY Apakah tamu dapat mengubah acara.
GUESTS_CAN_INVITE_OTHERS Apakah tamu dapat mengundang tamu lain.
GUESTS_CAN_SEE_GUESTS Apakah tamu dapat melihat daftar peserta.

Tambahkan acara

Saat aplikasi Anda menyisipkan acara baru, sebaiknya gunakan Intent INSERT, seperti yang dijelaskan dalam Menggunakan intent untuk menyisipkan acara. Namun, jika perlu, Anda dapat menyisipkan peristiwa secara langsung. Bagian ini menjelaskan cara melakukannya.

Berikut aturan untuk menyisipkan acara baru:

Berikut adalah contoh penyisipan acara. Hal ini dilakukan di UI thread untuk memudahkan. Dalam praktiknya, penyisipan dan pembaruan harus dilakukan di thread asinkron untuk memindahkan tindakan ke thread latar belakang. Untuk mengetahui informasi selengkapnya, 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 mengambil ID acara setelah acara dibuat. Ini adalah cara termudah untuk mendapatkan ID peristiwa. Anda sering kali memerlukan ID acara untuk melakukan operasi kalender lainnya—misalnya, untuk menambahkan tamu atau pengingat ke acara.

Peristiwa update

Jika aplikasi Anda ingin mengizinkan pengguna mengedit acara, sebaiknya gunakan Intent EDIT, seperti yang dijelaskan dalam Menggunakan intent untuk mengedit acara. Namun, jika perlu, Anda dapat mengedit peristiwa secara langsung. Untuk melakukan update Acara, Anda dapat memberikan _ID acara sebagai ID yang ditambahkan ke Uri (withAppendedId()) atau sebagai item pilihan pertama. Pilihan harus dimulai dengan "_id=?", dan selectionArg pertama harus berupa _ID acara. Anda juga dapat melakukan update menggunakan pilihan tanpa ID. Berikut adalah contoh cara memperbarui acara. Kode ini mengubah judul acara menggunakan pendekatan 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);

Hapus acara

Anda dapat menghapus peristiwa berdasarkan _ID-nya sebagai ID yang ditambahkan pada URI, atau dengan menggunakan pilihan standar. Jika menggunakan ID yang ditambahkan, Anda juga tidak dapat melakukan pemilihan. Ada dua versi penghapusan: sebagai aplikasi dan sebagai adaptor sinkronisasi. Penghapusan aplikasi menetapkan kolom deleted ke 1. Flag ini memberi tahu adaptor sinkronisasi bahwa baris telah dihapus dan penghapusan ini harus disebarkan ke server. Penghapusan adaptor sinkronisasi akan menghapus acara dari database beserta semua data terkaitnya. Berikut adalah contoh aplikasi yang menghapus acara 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 tabel CalendarContract.Attendees mewakili satu peserta atau tamu acara. Memanggil query() akan menampilkan daftar peserta untuk acara dengan EVENT_ID yang diberikan. EVENT_ID ini harus cocok dengan _ID peristiwa tertentu.

Tabel berikut mencantumkan kolom yang dapat ditulis. Saat menyisipkan peserta baru, Anda harus menyertakan semuanya kecuali ATTENDEE_NAME.

Konstanta Deskripsi
EVENT_ID ID peristiwa.
ATTENDEE_NAME Nama peserta.
ATTENDEE_EMAIL Alamat email peserta.
ATTENDEE_RELATIONSHIP

Hubungan peserta dengan acara. Salah satu:

ATTENDEE_TYPE

Jenis peserta. Salah satu:

ATTENDEE_STATUS

Status kehadiran peserta. Salah satu:

Menambahkan tamu

Berikut adalah contoh yang menambahkan satu tamu ke acara. Perhatikan bahwa EVENT_ID diperlukan:

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 tabel CalendarContract.Reminders mewakili satu pengingat untuk suatu acara. Memanggil query() akan menampilkan daftar pengingat untuk acara dengan EVENT_ID yang diberikan.

Tabel berikut mencantumkan kolom yang dapat ditulis untuk pengingat. Semuanya harus disertakan saat menyisipkan pengingat baru. Perhatikan bahwa adaptor sinkronisasi menentukan jenis pengingat yang didukungnya dalam tabel CalendarContract.Calendars. Untuk mengetahui detailnya, lihat ALLOWED_REMINDERS.

Konstanta Deskripsi
EVENT_ID ID peristiwa.
MINUTES Menit sebelum acara saat pengingat harus diaktifkan.
METHOD

Metode alarm, seperti yang ditetapkan di server. Salah satu:

Tambahkan pengingat

Contoh ini menambahkan pengingat ke acara. Pengingat akan diaktifkan 15 menit sebelum acara.

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 suatu peristiwa. Setiap baris dalam tabel ini mewakili satu kemunculan peristiwa. Tabel instance tidak dapat ditulis dan hanya menyediakan cara untuk mengkueri kemunculan peristiwa.

Tabel berikut mencantumkan beberapa kolom yang dapat Anda kueri untuk sebuah 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 berakhir instance, dalam milidetik UTC.
END_DAY Hari akhir Julian dari instance, relatif terhadap zona waktu Kalender.
END_MINUTE Menit akhir 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 diukur dari tengah malam, relatif terhadap zona waktu Kalender.

Membuat kueri tabel instance

Untuk membuat kueri tabel Instances, Anda harus menentukan rentang waktu untuk kueri di 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 dapat menggunakan intent yang didukung oleh aplikasi Kalender Android untuk menyerahkan operasi baca dan tulis ke aplikasi tersebut. Tabel berikut mencantumkan intent yang didukung oleh Penyedia Kalender:

Tindakan URI Deskripsi Konten bonus

VIEW

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

Anda juga dapat merujuk ke URI dengan CalendarContract.CONTENT_URI. Untuk contoh penggunaan intent ini, lihat Menggunakan intent untuk melihat data kalender.
Membuka kalender ke waktu yang ditentukan oleh <ms_since_epoch>. Tidak ada.

VIEW

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

Anda juga dapat merujuk ke URI dengan Events.CONTENT_URI. Untuk contoh penggunaan intent ini, lihat Menggunakan intent untuk melihat data kalender.
Melihat acara yang ditentukan oleh <event_id>. CalendarContract.EXTRA_EVENT_BEGIN_TIME


CalendarContract.EXTRA_EVENT_END_TIME
EDIT

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

Anda juga dapat merujuk ke URI dengan Events.CONTENT_URI. Untuk contoh penggunaan intent ini, lihat Menggunakan intent untuk mengedit acara.
Mengedit acara yang ditentukan oleh <event_id>. CalendarContract.EXTRA_EVENT_BEGIN_TIME


CalendarContract.EXTRA_EVENT_END_TIME
EDIT

INSERT

content://com.android.calendar/events

Anda juga dapat merujuk ke URI dengan Events.CONTENT_URI. Untuk contoh penggunaan intent ini, lihat Menggunakan intent untuk menyisipkan acara.
Buat acara. Salah satu tambahan yang tercantum dalam tabel berikut.

Tabel berikut mencantumkan intent tambahan yang didukung oleh Penyedia Kalender:

Intent Extra Deskripsi
Events.TITLE Nama peristiwa.
CalendarContract.EXTRA_EVENT_BEGIN_TIME Waktu mulai peristiwa dalam milidetik dari epoch.
CalendarContract.EXTRA_EVENT_END_TIME Waktu berakhir acara dalam milidetik dari epoch.
CalendarContract.EXTRA_EVENT_ALL_DAY Boolean yang menunjukkan bahwa acara berlangsung sepanjang hari. Nilai dapat berupa true atau false.
Events.EVENT_LOCATION Lokasi peristiwa.
Events.DESCRIPTION Deskripsi acara.
Intent.EXTRA_EMAIL Alamat email orang yang akan diundang sebagai daftar yang dipisahkan koma.
Events.RRULE Aturan pengulangan untuk acara.
Events.ACCESS_LEVEL Apakah acara bersifat pribadi atau publik.
Events.AVAILABILITY Apakah acara ini dihitung sebagai waktu sibuk atau waktu luang yang dapat dijadwalkan ulang.

Bagian berikut menjelaskan cara menggunakan intent ini.

Menggunakan intent untuk menyisipkan acara

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

Saat pengguna menjalankan aplikasi yang menggunakan pendekatan ini, aplikasi akan mengarahkan mereka ke Kalender untuk menyelesaikan penambahan acara. Intent INSERT menggunakan kolom tambahan untuk mengisi formulir secara otomatis dengan detail acara di Kalender. Pengguna kemudian dapat membatalkan acara, mengedit formulir sesuai kebutuhan, atau menyimpan acara ke kalender mereka.

Berikut adalah cuplikan kode yang menjadwalkan acara pada 19 Januari 2012, yang berjalan dari pukul 07.30 hingga 08.30. Perhatikan hal-hal berikut tentang cuplikan kode ini:

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 acara

Anda dapat memperbarui acara secara langsung, seperti yang dijelaskan dalam Memperbarui acara. 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 adalah contoh intent yang menetapkan judul baru untuk acara tertentu dan memungkinkan pengguna mengedit acara di 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 melihat data kalender

Penyedia Kalender menawarkan dua cara berbeda untuk menggunakan Intent VIEW:

  • Untuk membuka Kalender pada tanggal tertentu.
  • Untuk melihat acara.

Berikut adalah contoh yang menunjukkan cara membuka Kalender ke 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 contoh yang menunjukkan cara membuka acara untuk dilihat:

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 sedikit perbedaan dalam cara aplikasi dan adaptor sinkronisasi mengakses Penyedia Kalender:

  • Adaptor sinkronisasi harus menentukan bahwa adaptor tersebut adalah adaptor sinkronisasi dengan menetapkan CALLER_IS_SYNCADAPTER ke true.
  • Adaptor sinkronisasi perlu menyediakan ACCOUNT_NAME dan ACCOUNT_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. Sebagai perbandingan, adaptor sinkronisasi dapat mengakses tidak hanya kolom tersebut, tetapi juga banyak kolom lainnya, seperti warna kalender, zona waktu, tingkat akses, dan lokasi. Namun, adaptor sinkronisasi dibatasi untuk ACCOUNT_NAME dan ACCOUNT_TYPE yang ditentukannya.

Berikut adalah metode bantuan yang dapat Anda gunakan untuk menampilkan URI yang akan digunakan 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();
 }