ספק היומן הוא מאגר של אירועים ביומן של המשתמש. Calendar Provider API מאפשר לבצע פעולות של שאילתה, הוספה, עדכון ומחיקה של דברים כמו יומנים, אירועים, משתתפים ותזכורות.
אפליקציות ומתאמי סנכרון יכולים להשתמש ב-Calendar Provider API. הכללים משתנים בהתאם לסוג התוכנית שמבצעת את השיחות. המסמך הזה מתמקד בעיקר בשימוש ב-Calendar Provider API כאפליקציה. במאמר מתאמי סנכרון מוסבר במה מתאמי סנכרון שונים.
בדרך כלל, כדי לקרוא או לכתוב נתוני יומן, המניפסט של האפליקציה צריך לכלול את ההרשאות המתאימות, שמתוארות בקטע הרשאות משתמש. כדי להקל על ביצוע פעולות נפוצות, ספק היומן מציע קבוצה של Intent, כפי שמתואר בקטע Intent של יומן. ה-intent האלה מעבירים את המשתמשים לאפליקציית היומן כדי להוסיף, להציג ולערוך אירועים. המשתמש מבצע פעולה באפליקציית היומן ואז חוזר לאפליקציה המקורית. לכן, האפליקציה לא צריכה לבקש הרשאות, וגם לא צריכה לספק ממשק משתמש כדי להציג או ליצור אירועים.
מה צריך לעשות
ספקים לניהול גישה מאחסנים נתונים ומאפשרים לאפליקציות לגשת אליהם. הספקים לניהול גישה שמוצעים בפלטפורמת Android (כולל ספק היומן) בדרך כלל חושפים נתונים כקבוצה של טבלאות שמבוססות על מודל של מסד נתונים רלציוני, שבו כל שורה היא רשומה וכל עמודה היא נתונים מסוג ומשמעות מסוימים. באמצעות Calendar Provider API, אפליקציות ומתאמי סנכרון יכולים לקבל גישת קריאה/כתיבה לטבלאות של מסד הנתונים שבהן נשמרים נתוני היומן של המשתמש.
כל ספק לניהול גישה חושף URI ציבורי (עטוף כאובייקט Uri) שמזהה באופן ייחודי את קבוצת הנתונים שלו. ספק לניהול גישה ששולט בכמה קבוצות נתונים (כמה טבלאות) חושף URI נפרד לכל אחת מהן. כל מזהי ה-URI של הספקים מתחילים במחרוזת "content://". הוא מזהה את הנתונים ככאלה שנמצאים בשליטת ספק לניהול גישה. ספק היומן מגדיר קבועים לכתובות ה-URI של כל אחת מהמחלקות (הטבלאות) שלו. הפורמט של כתובות ה-URI האלה הוא <class>.CONTENT_URI. לדוגמה,
Events.CONTENT_URI.
איור 1 מציג ייצוג גרפי של מודל הנתונים של ספק היומן. הוא מציג את הטבלאות הראשיות ואת השדות שמקשרים ביניהן.
למשתמש יכולים להיות כמה יומנים, ויומנים שונים יכולים להיות משויכים לסוגים שונים של חשבונות (יומן Google, Exchange וכו').
CalendarContract מגדיר את מודל הנתונים של מידע שקשור ליומן ולאירועים. הנתונים האלה מאוחסנים בכמה טבלאות, שמפורטות בהמשך.
| טבלה (כיתה) | תיאור |
|---|---|
| הטבלה הזו מכילה את המידע הספציפי ליומן. כל שורה בטבלה הזו מכילה את הפרטים של יומן אחד, כמו השם, הצבע ופרטי הסנכרון. | |
CalendarContract.Events |
הטבלה הזו מכילה את המידע הספציפי לאירוע. כל שורה בטבלה הזו מכילה את המידע של אירוע אחד – למשל, שם האירוע, המיקום, שעת ההתחלה ושעת הסיום. האירוע יכול להתרחש פעם אחת או לחזור על עצמו כמה פעמים. המשתתפים, התזכורות והמאפיינים המורחבים מאוחסנים בטבלאות נפרדות.
לכל אחת מהן יש EVENT_ID שמפנה אל _ID בטבלה Events. |
CalendarContract.Instances |
בטבלה הזו מופיעות שעות ההתחלה והסיום של כל מופע של אירוע. כל שורה בטבלה הזו מייצגת אירוע אחד. באירועים חד-פעמיים יש מיפוי של 1:1 בין המופעים לאירועים. באירועים חוזרים, המערכת יוצרת באופן אוטומטי כמה שורות שתואמות למופעים השונים של האירוע. |
CalendarContract.Attendees |
הטבלה הזו מכילה את פרטי המשתתפים באירוע (האורחים). כל שורה מייצגת משתתף אחד באירוע. הוא מציין את סוג המשתתף ואת התשובה שלו לגבי ההשתתפות באירוע. |
CalendarContract.Reminders |
הטבלה הזו מכילה את נתוני ההתראות. כל שורה מייצגת התראה אחת על אירוע. לאירוע יכולות להיות כמה תזכורות. מספר התזכורות המקסימלי לכל אירוע מצוין ב-MAX_REMINDERS, ומוגדר על ידי מתאם הסנכרון שבבעלותו היומן הנתון. התזכורות מוגדרות בדקות לפני האירוע, ויש להן שיטה שקובעת איך המשתמש יקבל התראה. |
Calendar Provider API הוא כלי גמיש ורב-עוצמה. במקביל, חשוב לספק חוויית משתמש קצה טובה ולהגן על תקינות היומן והנתונים שבו. לכן, חשוב לזכור את הדברים הבאים כשמשתמשים ב-API:
- הוספה, עדכון וצפייה באירועים ביומן. כדי להוסיף, לשנות ולקרוא אירועים ישירות מספק היומן, צריך את ההרשאות המתאימות. עם זאת, אם אתם לא מפתחים אפליקציית יומן או מתאם סנכרון מלאים, אין צורך לבקש את ההרשאות האלה. במקום זאת, אתם יכולים להשתמש ב-Intent שנתמכים על ידי אפליקציית היומן של Android כדי להעביר פעולות קריאה וכתיבה לאפליקציה הזו. כשמשתמשים ב-Intent, האפליקציה מעבירה את המשתמשים לאפליקציית היומן כדי לבצע את הפעולה שנבחרה בטופס שמולא מראש. בסיום התהליך, המשתמשים מוחזרים לאפליקציה שלכם. אם תתכננו את האפליקציה כך שתבצע פעולות נפוצות דרך היומן, תספקו למשתמשים ממשק משתמש עקבי ויעיל. זו הגישה המומלצת. מידע נוסף זמין במאמר Calendar Intents.
- מתאמי סנכרון. מתאם סנכרון מסנכרן את נתוני היומן במכשיר של המשתמש עם שרת או מקור נתונים אחר. בטבלאות
CalendarContract.Calendarsו-CalendarContract.Eventsיש עמודות ששמורות לשימוש של מתאמי הסנכרון. הספק והאפליקציות לא אמורים לשנות אותם. למעשה, הם לא גלויים אלא אם ניגשים אליהם כמתאם סנכרון. מידע נוסף על מתאמי סנכרון זמין במאמר מתאמי סנכרון.
הרשאות המשתמשים
כדי לקרוא נתונים מהיומן, אפליקציה צריכה לכלול את ההרשאה READ_CALENDAR בקובץ המניפסט שלה. הוא חייב לכלול את ההרשאה WRITE_CALENDAR כדי למחוק, להוסיף או לעדכן נתונים ביומן:
<?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>
טבלת היומנים
הטבלה CalendarContract.Calendars מכילה פרטים של יומנים ספציפיים. אפליקציה ומתאם סנכרון יכולים לכתוב בעמודות הבאות של Calendars.
רשימה מלאה של השדות הנתמכים מופיעה בחומר העזר בנושא CalendarContract.Calendars.
| קבוע | תיאור |
|---|---|
NAME |
שם היומן. |
CALENDAR_DISPLAY_NAME |
השם של היומן שמוצג למשתמש. |
VISIBLE |
ערך בוליאני שמציין אם היומן נבחר להצגה. הערך 0 מציין שאירועים שמשויכים ליומן הזה לא יוצגו. הערך 1 מציין שצריך להציג אירועים שמשויכים ליומן הזה. הערך הזה משפיע על יצירת השורות בטבלה CalendarContract.Instances. |
SYNC_EVENTS |
ערך בוליאני שמציין אם צריך לסנכרן את היומן ולשמור את האירועים שלו במכשיר. הערך 0 מציין שהיומן לא מסונכרן והאירועים שלו לא נשמרים במכשיר. הערך 1 מציין שהאירועים ביומן הזה מסונכרנים ונשמרים במכשיר. |
צריך לכלול סוג חשבון בכל הפעולות
אם שולחים שאילתה לגבי Calendars.ACCOUNT_NAME, צריך לכלול גם את Calendars.ACCOUNT_TYPE בבחירה. הסיבה לכך היא שחשבון נחשב לייחודי רק אם יש לו גם ACCOUNT_NAME וגם ACCOUNT_TYPE. הערך ACCOUNT_TYPE הוא המחרוזת שתואמת למאמת החשבון שבו השתמשתם כשנרשמתם לחשבון באמצעות AccountManager. יש גם סוג מיוחד של חשבון שנקרא ACCOUNT_TYPE_LOCAL ליומנים שלא משויכים לחשבון במכשיר.
חשבונות ACCOUNT_TYPE_LOCAL לא מסתנכרנים.
שאילתה על יומן
בדוגמה הבאה אפשר לראות איך מקבלים את היומנים שבבעלות משתמש מסוים. לשם הפשטות, בדוגמה הזו פעולת השאילתה מוצגת בשרשור של ממשק המשתמש ("השרשור הראשי"). בפועל, צריך לעשות את זה ב-thread אסינכרוני במקום ב-thread הראשי. למידע נוסף, ראו טוענים. אם אתם לא רק קוראים נתונים אלא גם משנים אותם, קראו את 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;
בחלק הבא של הדוגמה, אתם בונים את השאילתה. הבחירה מציינת את הקריטריונים לשאילתה. בדוגמה הזו, השאילתה מחפשת יומנים עם ACCOUNT_NAME "hera@example.com", ACCOUNT_TYPE "com.example" ו-OWNER_ACCOUNT "hera@example.com". אם רוצים לראות את כל היומנים שמשתמש צפה בהם, ולא רק את היומנים שבבעלות המשתמש, צריך להשמיט את OWNER_ACCOUNT.
השאילתה מחזירה אובייקט Cursor שאפשר להשתמש בו כדי לעבור על קבוצת התוצאות שהוחזרה על ידי השאילתה במסד הנתונים. למידע נוסף על שימוש בשאילתות בספקים לניהול גישה, ראו ספקים לניהול גישה.
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);
בקטע הבא נעשה שימוש בסמן כדי לעבור על קבוצת התוצאות. היא משתמשת בקבועים שהוגדרו בתחילת הדוגמה כדי להחזיר את הערכים של כל שדה.
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... ... }
שינוי יומן
כדי לעדכן יומן, אפשר לציין את ה-_ID של היומן כמזהה שמצורף ל-URI (withAppendedId()) או כפריט הבחירה הראשון. הבחירה צריכה להתחיל ב-"_id=?", וה-selectionArg הראשון צריך להיות ה-_ID של היומן.
אפשר גם לבצע עדכונים על ידי קידוד המזהה ב-URI. בדוגמה הזו משנים את השם המוצג של היומן באמצעות הגישה (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);
הוספת יומן
היומנים מיועדים לניהול בעיקר על ידי מתאם סנכרון, ולכן צריך להוסיף יומנים חדשים רק כמתאם סנכרון. ברוב המקרים, אפליקציות יכולות לבצע רק שינויים שטחיים ביומנים, כמו שינוי השם המוצג. אם אפליקציה צריכה ליצור יומן מקומי, היא יכולה לעשות זאת על ידי הוספת היומן כמתאם סנכרון, באמצעות ACCOUNT_TYPE של ACCOUNT_TYPE_LOCAL.
ACCOUNT_TYPE_LOCAL
הוא סוג חשבון מיוחד ליומנים שלא משויכים לחשבון במכשיר. יומנים מהסוג הזה לא מסונכרנים עם שרת. לדיון על מתאמי סנכרון, ראו מתאמי סנכרון.
טבלת אירועים
הטבלה CalendarContract.Events מכילה פרטים על אירועים ספציפיים. כדי להוסיף, לעדכן או למחוק אירועים, האפליקציה צריכה לכלול את ההרשאה WRITE_CALENDAR בקובץ המניפסט שלה.
אפשר לכתוב בעמודות הבאות של Events גם באמצעות אפליקציה וגם באמצעות מתאם סנכרון. רשימה מלאה של השדות הנתמכים מופיעה בחומר העזר בנושא CalendarContract.Events.
| קבוע | תיאור |
|---|---|
CALENDAR_ID |
_ID של היומן שהאירוע שייך אליו. |
ORGANIZER |
כתובת האימייל של מארגן האירוע (הבעלים). |
TITLE |
שם האירוע. |
EVENT_LOCATION |
המקום שבו האירוע מתקיים. |
DESCRIPTION |
תיאור האירוע. |
DTSTART |
השעה שבה האירוע מתחיל, במילישניות לפי שעון UTC מאז תחילת התקופה. |
DTEND |
השעה שבה האירוע מסתיים, במילישניות לפי שעון UTC מאז תחילת התקופה. |
EVENT_TIMEZONE |
אזור הזמן של האירוע. |
EVENT_END_TIMEZONE |
אזור הזמן של שעת הסיום של האירוע. |
DURATION |
משך האירוע בפורמט RFC5545.
לדוגמה, הערך "PT1H" מציין שהאירוע יימשך שעה, והערך "P2W" מציין שהאירוע יימשך שבועיים. |
ALL_DAY |
הערך 1 מציין שהאירוע נמשך כל היום, לפי אזור הזמן המקומי. הערך 0 מציין שזה אירוע רגיל שיכול להתחיל ולהסתיים בכל שעה במהלך היום. |
RRULE |
הכלל לחזרה על האירוע. לדוגמה, "FREQ=WEEKLY;COUNT=10;WKST=SU". דוגמאות נוספות מופיעות במפרט RFC5545. |
RDATE |
תאריכי החזרה של האירוע.
בדרך כלל משתמשים ב-RDATE בשילוב עם RRULE כדי להגדיר קבוצה מצטברת של מופעים חוזרים. למידע נוסף, אפשר לעיין במפרט RFC5545. |
AVAILABILITY |
אם האירוע הזה נחשב כזמן עסוק או כזמן פנוי שאפשר לקבוע בו אירועים אחרים. |
GUESTS_CAN_MODIFY |
אם המשתתפים יכולים לשנות את האירוע. |
GUESTS_CAN_INVITE_OTHERS |
אם המשתתפים יכולים להזמין משתתפים אחרים. |
GUESTS_CAN_SEE_GUESTS |
אם המשתתפים יכולים לראות את רשימת המשתתפים. |
הוספת אירועים
כשהאפליקציה מוסיפה אירוע חדש, מומלץ להשתמש ב-Intent של INSERT, כמו שמתואר בקטע שימוש ב-Intent להוספת אירוע. אבל אם אתם צריכים, אתם יכולים להוסיף אירועים ישירות. בקטע הזה מוסבר איך לעשות את זה.
אלה הכללים להוספת אירוע חדש:
- צריך לכלול את
CALENDAR_IDו-DTSTART. - חובה לכלול
EVENT_TIMEZONE. כדי לקבל רשימה של מזהי אזורי הזמן שמותקנים במערכת, משתמשים ב-getAvailableIDs(). חשוב לזכור שהכלל הזה לא חל אם מוסיפים אירוע באמצעות Intent שלINSERT, כפי שמתואר בקטע שימוש ב-Intent להוספת אירוע – בתרחיש הזה, מסופק אזור זמן כברירת מחדל. - באירועים לא חוזרים, צריך לכלול את
DTEND. - באירועים חוזרים, צריך לכלול את
DURATIONבנוסף ל-RRULEאו ל-RDATE. שימו לב שהכלל הזה לא חל אם אתם מוסיפים אירוע באמצעות Intent שלINSERT, כפי שמתואר בקטע שימוש ב-Intent להוספת אירוע – בתרחיש הזה, אתם יכולים להשתמש ב-RRULEבשילוב עםDTSTARTו-DTEND, ואפליקציית היומן ממירה אותו למשך זמן באופן אוטומטי.
הנה דוגמה להוספת אירוע. הפעולה הזו מתבצעת בשרשור של ממשק המשתמש כדי לפשט את התהליך. בפועל, צריך לבצע הוספות ועדכונים בשרשור אסינכרוני כדי להעביר את הפעולה לשרשור ברקע. מידע נוסף זמין במאמר 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 // //
הערה: בדוגמה הזו אפשר לראות איך מזהה האירוע נשמר אחרי שהאירוע נוצר. זו הדרך הקלה ביותר לקבל מזהה אירוע. בדרך כלל צריך את מזהה האירוע כדי לבצע פעולות אחרות ביומן, למשל כדי להוסיף משתתפים או תזכורות לאירוע.
אירועי עדכון
אם אתם רוצים לאפשר למשתמשים לערוך אירוע באפליקציה, מומלץ להשתמש ב-Intent של EDIT, כמו שמתואר בקטע שימוש ב-Intent כדי לערוך אירוע.
עם זאת, אם אתם צריכים, אתם יכולים לערוך אירועים ישירות. כדי לעדכן אירוע, אפשר לספק את ה-_ID של האירוע כמזהה שמצורף ל-URI (withAppendedId()) או כפריט הבחירה הראשון.
הבחירה צריכה להתחיל ב-"_id=?", וה-selectionArg הראשון צריך להיות ה-_ID של האירוע. אפשר גם לבצע עדכונים באמצעות בחירה ללא מזהה. הנה דוגמה לעדכון אירוע. הוא משנה את שם האירוע לפי הגישה של
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);
מחיקת אירועים
אפשר למחוק אירוע לפי ה-_ID שלו כמזהה שמצורף ל-URI, או באמצעות בחירה רגילה. אם משתמשים במזהה שנוסף, אי אפשר לבצע גם בחירה.
יש שתי גרסאות של מחיקה: כאפליקציה וכמתאם סנכרון. מחיקה של אפליקציה מגדירה את העמודה deleted ל-1. הדגל הזה מציין למתאם הסנכרון שהשורה נמחקה, ושהמחיקה הזו צריכה להתפשט לשרת. מחיקה באמצעות מתאם סנכרון מסירה את האירוע ממסד הנתונים יחד עם כל הנתונים שמשויכים אליו. הנה דוגמה לאפליקציה שמוחקת אירוע באמצעות _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);
טבלת המשתתפים
כל שורה בטבלה CalendarContract.Attendees מייצגת משתתף או אורח אחד באירוע. הקריאה לפונקציה query() מחזירה רשימה של המשתתפים באירוע עם הערך הנתון של EVENT_ID.
הערך של EVENT_ID
צריך להיות זהה לערך של _ID באירוע מסוים.
בטבלה הבאה מפורטים השדות שניתן לכתוב בהם. כשמוסיפים משתתף חדש, צריך לכלול את כל השדות חוץ מ-ATTENDEE_NAME.
| קבוע | תיאור |
|---|---|
EVENT_ID |
המזהה של האירוע. |
ATTENDEE_NAME |
שם המשתתף. |
ATTENDEE_EMAIL |
כתובת האימייל של המשתתף. |
ATTENDEE_RELATIONSHIP |
הקשר של המשתתף לאירוע. אחת מהאפשרויות: |
ATTENDEE_TYPE |
סוג המשתתף. אחת מהאפשרויות: |
ATTENDEE_STATUS |
סטטוס הנוכחות של המשתתף. אחת מהאפשרויות: |
הוספת משתתפים
הנה דוגמה להוספת משתתף אחד לאירוע. שימו לב שחובה להזין את הערך
EVENT_ID
:
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);
טבלת התזכורות
כל שורה בטבלה CalendarContract.Reminders מייצגת תזכורת אחת לאירוע. קריאה ל-query() מחזירה רשימה של תזכורות לאירוע עם ה-EVENT_ID שצוין.
בטבלה הבאה מפורטים השדות שניתן לכתוב בהם בתזכורות. צריך לכלול את כולם כשמוסיפים תזכורת חדשה. חשוב לזכור שמתאמי סנכרון מציינים את סוגי התזכורות שהם תומכים בהם בטבלה CalendarContract.Calendars. פרטים נוספים מופיעים בכתובת ALLOWED_REMINDERS.
| קבוע | תיאור |
|---|---|
EVENT_ID |
המזהה של האירוע. |
MINUTES |
מספר הדקות לפני האירוע שבהן התזכורת אמורה לפעול. |
METHOD |
שיטת ההתראה, כפי שהוגדרה בשרת. אחת מהאפשרויות: |
הוסף תזכורות
בדוגמה הזו מוסיפים תזכורת לאירוע. התזכורת מופעלת 15 דקות לפני האירוע.
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);
טבלת המכונות
הטבלה CalendarContract.Instances מכילה את זמני ההתחלה והסיום של מופעי האירוע. כל שורה בטבלה הזו מייצגת אירוע אחד. אי אפשר לכתוב בטבלת המופעים, והיא משמשת רק כדי לשלוח שאילתות לגבי מופעי אירועים.
בטבלה הבאה מפורטים חלק מהשדות שאפשר לשלוח לגביהם שאילתות במכונה. שימו לב שאזור הזמן מוגדר על ידי KEY_TIMEZONE_TYPE ו-KEY_TIMEZONE_INSTANCES.
| קבוע | תיאור |
|---|---|
BEGIN |
שעת ההתחלה של המופע, באלפיות השנייה לפי שעון UTC. |
END |
שעת הסיום של המופע, באלפיות השנייה לפי שעון UTC. |
END_DAY |
היום היוליאני שבו המופע מסתיים, ביחס לאזור הזמן של היומן. |
END_MINUTE |
הדקה שבה מסתיים המופע, החל מחצות באזור הזמן של היומן. |
EVENT_ID |
ה-_ID של האירוע במקרה הזה. |
START_DAY |
היום הראשון של המופע לפי הלוח היוליאני, ביחס לאזור הזמן של היומן. |
START_MINUTE |
הדקה שבה מתחיל המופע, החל מחצות, ביחס לאזור הזמן של היומן. |
הרצת שאילתה על טבלת המופעים
כדי לשלוח שאילתה לטבלה Instances, צריך לציין טווח זמן לשאילתה ב-URI. בדוגמה הזו, CalendarContract.Instances מקבל גישה לשדה TITLE באמצעות ההטמעה של הממשק CalendarContract.EventsColumns.
במילים אחרות, TITLE מוחזר דרך תצוגת מסד נתונים, ולא באמצעות שאילתה בטבלה הגולמית 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())); } }
כוונות ביומן Google
לאפליקציה שלכם לא נדרשות הרשאות כדי לקרוא ולכתוב נתונים ביומן. במקום זאת, היא יכולה להשתמש ב-Intent שנתמכים על ידי אפליקציית היומן של Android כדי להעביר פעולות קריאה וכתיבה לאפליקציה הזו. בטבלה הבאה מפורטים ה-intent שנתמכים על ידי ספק היומן:
| פעולה | URI | תיאור | תוספות |
|---|---|---|---|
VIEW |
CalendarContract.CONTENT_URI.
דוגמה לשימוש ב-Intent הזה מופיעה במאמר שימוש ב-Intent כדי להציג נתונים ביומן.
|
פתיחת היומן בשעה שצוינה על ידי <ms_since_epoch>. |
ללא. |
Events.CONTENT_URI.
דוגמה לשימוש ב-Intent הזה מופיעה במאמר שימוש ב-Intent כדי להציג נתונים ביומן.
|
הצגת האירוע שצוין על ידי <event_id>. |
CalendarContract.EXTRA_EVENT_BEGIN_TIMECalendarContract.EXTRA_EVENT_END_TIME |
|
EDIT |
Events.CONTENT_URI.
דוגמה לשימוש ב-Intent הזה מופיעה בקטע שימוש ב-Intent כדי לערוך אירוע.
|
עריכת האירוע שצוין על ידי <event_id>. |
CalendarContract.EXTRA_EVENT_BEGIN_TIMECalendarContract.EXTRA_EVENT_END_TIME |
EDIT INSERT |
Events.CONTENT_URI.
דוגמה לשימוש ב-Intent הזה מופיעה במאמר שימוש ב-Intent להוספת אירוע.
|
יוצרים אירוע. | כל אחד מהתוספים שמפורטים בטבלה הבאה. |
בטבלה הבאה מפורטים ה-extras של ה-intent שנתמכים על ידי ספק היומן:
| Intent Extra | תיאור |
|---|---|
Events.TITLE |
שם האירוע. |
CalendarContract.EXTRA_EVENT_BEGIN_TIME |
שעת ההתחלה של האירוע באלפיות השנייה מהתקופה. |
CalendarContract.EXTRA_EVENT_END_TIME |
שעת הסיום של האירוע באלפיות השנייה מראשית זמן יוניקס (Unix epoch). |
CalendarContract.EXTRA_EVENT_ALL_DAY |
ערך בוליאני שמציין אם האירוע הוא של יום שלם. הערך יכול להיות true או false. |
Events.EVENT_LOCATION |
המיקום של האירוע. |
Events.DESCRIPTION |
תיאור האירוע. |
Intent.EXTRA_EMAIL |
כתובות האימייל של האנשים שרוצים להזמין, ברשימה מופרדת בפסיקים. |
Events.RRULE |
הכלל לחזרה על האירוע. |
Events.ACCESS_LEVEL |
אם האירוע פרטי או ציבורי. |
Events.AVAILABILITY |
אם האירוע הזה נחשב כזמן עסוק או כזמן פנוי שאפשר לקבוע בו אירועים אחרים. |
בקטעים הבאים מוסבר איך להשתמש ב-Intent האלה.
שימוש ב-Intent כדי להוסיף אירוע
באמצעות Intent של INSERT, האפליקציה יכולה להעביר את המשימה של הוספת האירוע ליומן עצמו.
בגישה הזו, האפליקציה לא צריכה לכלול את ההרשאה WRITE_CALENDAR בקובץ המניפסט שלה.
כשמשתמשים מפעילים אפליקציה שמשתמשת בגישה הזו, האפליקציה מפנה אותם ליומן כדי לסיים את הוספת האירוע. ה-Intent של INSERT משתמש בשדות נוספים כדי לאכלס מראש טופס עם פרטי האירוע ביומן. המשתמשים יכולים לבטל את האירוע, לערוך את הטופס לפי הצורך או לשמור את האירוע ביומנים שלהם.
קטע הקוד הבא מתזמן אירוע ב-19 בינואר 2012, שפועל בין השעות 7:30 ל-8:30. שימו לב לפרטים הבאים לגבי קטע הקוד הזה:
- הוא מציין את
Events.CONTENT_URIבתור ה-URI. - הוא משתמש בשדות הנוספים
CalendarContract.EXTRA_EVENT_BEGIN_TIMEו-CalendarContract.EXTRA_EVENT_END_TIMEכדי לאכלס מראש את הטופס עם שעת האירוע. הערכים של הזמנים האלה צריכים להיות באלפיות השנייה לפי זמן UTC, החל מתקופת זמן המערכת. - הוא משתמש בשדה הנוסף
Intent.EXTRA_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);
שימוש ב-Intent כדי לערוך אירוע
אתם יכולים לעדכן אירוע ישירות, כמו שמתואר בקטע עדכון אירועים. אבל שימוש ב-Intent EDIT מאפשר לאפליקציה שאין לה הרשאה להעביר את עריכת האירוע לאפליקציית היומן.
כשהמשתמשים מסיימים לערוך את האירוע ביומן, הם מוחזרים לאפליקציה המקורית.
הנה דוגמה ל-Intent שמגדיר שם חדש לאירוע מסוים ומאפשר למשתמשים לערוך את האירוע ביומן.
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);
שימוש ב-Intent כדי להציג נתונים מהיומן
ספק היומן מציע שתי דרכים שונות להשתמש ב-Intent של VIEW:
- כדי לפתוח את היומן בתאריך מסוים.
- כדי לראות אירוע:
הנה דוגמה שמראה איך לפתוח את היומן בתאריך מסוים:
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);
הדוגמה הבאה מראה איך לפתוח אירוע כדי לצפות בו:
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);
מתאמי סנכרון
יש רק הבדלים קלים בין הגישה של אפליקציה לבין הגישה של מתאם סנכרון לספק היומן:
- כדי לציין שמתאם סנכרון הוא מתאם סנכרון, צריך להגדיר את
CALLER_IS_SYNCADAPTERל-true. - מתאם סנכרון צריך לספק
ACCOUNT_NAMEו-ACCOUNT_TYPEכפרמטרים של שאילתה ב-URI. - למתאם סנכרון יש גישת כתיבה ליותר עמודות מאשר לאפליקציה או לווידג'ט.
לדוגמה, אפליקציה יכולה לשנות רק כמה מאפיינים של יומן, כמו השם, השם המוצג, הגדרת החשיפה והאם היומן מסונכרן. לעומת זאת, מתאם סנכרון יכול לגשת לא רק לעמודות האלה, אלא גם לעמודות רבות אחרות, כמו צבע היומן, אזור הזמן, רמת הגישה והמיקום.
עם זאת, מתאם סנכרון מוגבל ל-
ACCOUNT_NAMEול-ACCOUNT_TYPEשצוינו.
הנה שיטת עזר שבה אפשר להשתמש כדי להחזיר URI לשימוש עם מתאם סנכרון:
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(); }