הספק של אנשי הקשר הוא רכיב Android גמיש ורב-עוצמה שמנהל את מאגר הנתונים המרכזי של המכשיר לגבי אנשים. האפליקציה לניהול אנשי הקשר היא מקור הנתונים שמוצגים באפליקציה לניהול אנשי הקשר במכשיר. אפשר גם לגשת לנתונים שלה באפליקציה שלכם ולהעביר נתונים בין המכשיר לשירותים אונליין. הספק תומך במגוון רחב של מקורות נתונים ומנסה לנהל כמה שיותר נתונים לכל אדם, ולכן הארגון שלו מורכב. לכן, ה-API של הספק כולל קבוצה נרחבת של מחלקות של ערכים קבועים וממשקים שמאפשרים גם לאחזר נתונים וגם לשנות אותם.
במדריך הזה נסביר:
- המבנה הבסיסי של ספק.
- איך לאחזר נתונים מהספק.
- איך לשנות נתונים בספק.
- איך לכתוב מתאם סנכרון כדי לסנכרן נתונים מהשרת עם ניהול אנשי הקשר.
המדריך הזה מניח שאתם מכירים את היסודות של ספקים לניהול גישה ב-Android. מידע נוסף על ספקים לניהול גישה ב-Android זמין במדריך ספקים לניהול גישה – מידע בסיסי.
ארגון של ניהול אנשי הקשר
הספק לניהול אנשי הקשר הוא רכיב של ספק לניהול גישה ב-Android. הוא מכיל שלושה סוגים של נתונים על אדם, שכל אחד מהם תואם לטבלה שמציע הספק, כפי שמוצג באיור 1:
איור 1. מבנה הטבלה של ניהול אנשי הקשר.
שלוש הטבלאות מכונות בדרך כלל בשמות של המחלקות של הערכים הקבועים שלהן. המחלקות מגדירות קבועים ל-URI של תוכן, שמות עמודות וערכי עמודות שבהם משתמשות הטבלאות:
-
טבלה של
ContactsContract.Contacts - שורות שמייצגות אנשים שונים, על סמך צבירות של שורות נתונים גולמיים של אנשי קשר.
-
טבלה של
ContactsContract.RawContacts - שורות שמכילות סיכום של נתוני אדם, ספציפיים לסוג ולחשבון של המשתמש.
-
טבלה של
ContactsContract.Data - שורות שמכילות את הפרטים של הנתונים הגולמיים של איש הקשר, כמו כתובות אימייל או מספרי טלפון.
הטבלאות האחרות שמיוצגות על ידי מחלקות של ערכים קבועים (contract class) ב-ContactsContract הן טבלאות עזר שמשמשות את ניהול אנשי הקשר כדי לנהל את תפעול ה-IT שלו או לתמוך בפונקציות ספציפיות באפליקציות של אנשי הקשר או הטלפוניה במכשיר.
נתונים גולמיים של אנשי קשר
נתונים גולמיים של איש קשר מייצגים נתונים של אדם שמגיעים מסוג חשבון אחד ומשם חשבון אחד. מכיוון שניהול אנשי הקשר מאפשר להשתמש ביותר משירות אונליין אחד כמקור הנתונים של אדם מסוים, הוא מאפשר כמה נתונים גולמיים של אנשי קשר לאותו אדם. כמה נתונים גולמיים של איש קשר גם מאפשרים למשתמש לשלב נתונים של אדם מסוים מיותר מחשבון אחד מאותו סוג חשבון.
רוב הנתונים של איש קשר גולמי לא מאוחסנים בטבלה ContactsContract.RawContacts. במקום זאת, הוא מאוחסן בשורה אחת או יותר בטבלה ContactsContract.Data. לכל שורת נתונים יש עמודה Data.RAW_CONTACT_ID שמכילה את הערך RawContacts._ID של שורת ההורה ContactsContract.RawContacts.
עמודות חשובות של נתונים גולמיים של אנשי קשר
העמודות החשובות בטבלה ContactsContract.RawContacts מפורטות בטבלה 1. חשוב לקרוא את ההערות שמופיעות אחרי הטבלה:
טבלה 1. עמודות חשובות של נתונים גולמיים של אנשי קשר.
| שם העמודה | שימוש | הערות |
|---|---|---|
ACCOUNT_NAME
|
שם החשבון של סוג החשבון שהוא המקור של הנתונים הגולמיים של איש הקשר הזה.
לדוגמה, שם החשבון של חשבון Google הוא אחת מכתובות ה-Gmail של בעלי המכשיר. מידע נוסף זמין בערך הבא של ACCOUNT_TYPE.
|
הפורמט של השם הזה ספציפי לסוג החשבון. הוא לא בהכרח כתובת אימייל. |
ACCOUNT_TYPE
|
סוג החשבון שהוא המקור של הנתונים הגולמיים של איש הקשר הזה. לדוגמה, סוג החשבון של חשבון Google הוא com.google. תמיד צריך להגדיר את סוג החשבון עם מזהה דומיין של דומיין שבבעלותכם או בשליטתכם. כך תוכלו לוודא שסוג החשבון שלכם ייחודי.
|
לסוג חשבון שמציע נתוני אנשי קשר יש בדרך כלל מתאם סנכרון משויך שמסתנכרן עם ניהול אנשי הקשר. |
DELETED
|
הדגל "נמחק" של נתונים גולמיים של איש קשר. | הדגל הזה מאפשר לניהול אנשי הקשר לשמור את השורה באופן פנימי עד שמתאמי הסנכרון יוכלו למחוק את השורה מהשרתים שלהם, ואז למחוק את השורה מהמאגר. |
הערות
הערות חשובות לגבי הטבלה ContactsContract.RawContacts:
-
השם של נתונים גולמיים של איש קשר לא מאוחסן בשורה שלו ב-
ContactsContract.RawContacts. במקום זאת, הוא מאוחסן בטבלהContactsContract.Data, בשורהContactsContract.CommonDataKinds.StructuredName. לנתונים גולמיים של איש קשר יש רק שורה אחת מהסוג הזה בטבלהContactsContract.Data. -
זהירות: כדי להשתמש בנתוני החשבון שלכם בשורה של נתונים גולמיים של איש קשר, קודם צריך לרשום אותם ב-
AccountManager. כדי לעשות את זה, צריך לבקש מהמשתמשים להוסיף את סוג החשבון ואת שם החשבון שלהם לרשימת החשבונות. אם לא תעשו את זה, ניהול אנשי הקשר ימחק באופן אוטומטי את השורה של הנתונים הגולמיים של איש הקשר.לדוגמה, אם אתם רוצים שהאפליקציה תנהל את נתוני אנשי הקשר של השירות מבוסס-האינטרנט שלכם עם הדומיין
com.example.dataservice, וחשבון המשתמש בשירות שלכם הואbecky.sharp@dataservice.example.com, המשתמש צריך קודם להוסיף את "סוג" החשבון (com.example.dataservice) ואת "שם" החשבון (becky.smart@dataservice.example.com) לפני שהאפליקציה תוכל להוסיף שורות של נתונים גולמיים של אנשי קשר. אפשר להסביר את הדרישה הזו למשתמש במסמכים, או לבקש מהמשתמש להוסיף את הסוג והשם, או את שניהם. בקטע הבא מוסברים בפירוט סוגי החשבונות ושמות החשבונות.
מקורות של נתונים גולמיים של אנשי קשר
כדי להבין איך פועלים נתונים גולמיים של אנשי קשר, נניח שלמשתמשת "אמילי דיקינסון" יש את שלושת חשבונות המשתמש הבאים שמוגדרים במכשיר שלה:
emily.dickinson@gmail.comemilyd@gmail.com- חשבון הטוויטר "belle_of_amherst"
המשתמש הזה הפעיל את האפשרות סנכרון אנשי קשר בכל שלושת החשבונות האלה בהגדרות חשבונות.
נניח שאמילי דיקינסון פותחת חלון דפדפן, נכנסת ל-Gmail בתור emily.dickinson@gmail.com, פותחת את אנשי הקשר ומוסיפה את "תומאס היגינסון". מאוחר יותר, היא מתחברת ל-Gmail בתור emilyd@gmail.com ושולחת אימייל אל "Thomas Higginson", והוא מתווסף אוטומטית כאיש קשר. היא גם עוקבת אחרי "colonel_tom" (מזהה הטוויטר של תומאס היגינסון) בטוויטר.
כתוצאה מהפעולה הזו, ניהול אנשי הקשר יוצר שלושה נתונים גולמיים של איש קשר:
-
נתונים גולמיים של איש קשר בשם "תומס היגינסון" שמשויך אל
emily.dickinson@gmail.com. סוג חשבון המשתמש הוא Google. -
נתונים גולמיים נוספים של איש הקשר "Thomas Higginson" שמשויכים אל
emilyd@gmail.com. סוג חשבון המשתמש הוא גם Google. יש עוד נתונים גולמיים של איש קשר, למרות שהשם זהה לשם הקודם, כי האדם נוסף לחשבון משתמש אחר. - נתונים גולמיים שלישיים של איש הקשר "Thomas Higginson" שמשויכים ל-"belle_of_amherst". סוג חשבון המשתמש הוא טוויטר.
נתונים
כמו שצוין קודם, הנתונים של איש קשר גולמי מאוחסנים בשורה ב-ContactsContract.Data שמקושרת לערך _ID של איש הקשר הגולמי. כך, נתונים גולמיים של איש קשר אחד יכולים לכלול כמה מופעים של אותו סוג נתונים, כמו כתובות אימייל או מספרי טלפון. לדוגמה, אם ל"תומאס היגינסון" ב-emilyd@gmail.com (השורה של הנתונים הגולמיים של איש הקשר תומאס היגינסון שמשויכת לחשבון Google emilyd@gmail.com) יש כתובת אימייל פרטית thigg@gmail.com וכתובת אימייל בעבודה thomas.higginson@gmail.com, ניהול אנשי הקשר מאחסן את שתי השורות של כתובות האימייל ומקשר את שתיהן לנתונים הגולמיים של איש הקשר.
שימו לב שסוגים שונים של נתונים מאוחסנים בטבלה אחת. השורות של השם המוצג, מספר הטלפון, כתובת האימייל, הכתובת למשלוח דואר, התמונה ופרטי האתר נמצאות בטבלה ContactsContract.Data. כדי לעזור לכם לנהל את זה, בטבלה ContactsContract.Data יש עמודות עם שמות תיאוריים ועמודות עם שמות כלליים. התוכן של עמודה עם שם תיאורי הוא בעל משמעות זהה, בלי קשר לסוג הנתונים בשורה, ואילו התוכן של עמודה עם שם כללי הוא בעל משמעויות שונות בהתאם לסוג הנתונים.
שמות תיאוריים של עמודות
הנה כמה דוגמאות לשמות תיאוריים של עמודות:
-
RAW_CONTACT_ID -
הערך של העמודה
_IDשל הנתונים הגולמיים של איש הקשר עבור הנתונים האלה. -
MIMETYPE -
סוג הנתונים שמאוחסנים בשורה הזו, מבוטא כסוג MIME מותאם אישית. ניהול אנשי הקשר משתמש בסוגי ה-MIME שמוגדרים במחלקות המשנה של
ContactsContract.CommonDataKinds. סוגי ה-MIME האלה הם קוד פתוח, וכל אפליקציה או מתאם סנכרון שפועלים עם ניהול אנשי הקשר יכולים להשתמש בהם. -
IS_PRIMARY -
אם סוג כזה של שורת נתונים יכול להופיע יותר מפעם אחת בנתונים גולמיים של איש קשר, העמודה
IS_PRIMARYמסמנת את שורת הנתונים שמכילה את הנתונים הראשיים של הסוג. לדוגמה, אם המשתמש לוחץ לחיצה ארוכה על מספר טלפון של איש קשר ובוחר באפשרות הגדרה כברירת מחדל, אז בעמודהIS_PRIMARYבשורהContactsContract.Dataשמכילה את המספר הזה מוגדר ערך שאינו אפס.
שמות כלליים של עמודות
יש 15 עמודות גנריות שנקראות DATA1 עד DATA15 שזמינות לכלל המשתמשים, ועוד 4 עמודות גנריות שנקראות SYNC1 עד SYNC4 שרק מתאמי סנכרון יכולים להשתמש בהן. הקבועים של שמות העמודות הכלליים תמיד פועלים, בלי קשר לסוג הנתונים שהשורה מכילה.
העמודה DATA1 נוספה לאינדקס. ספק אנשי הקשר תמיד משתמש בעמודה הזו לנתונים שהספק מצפה שיהיו היעד הנפוץ ביותר של שאילתה. לדוגמה, בשורה של אימייל, העמודה הזו מכילה את כתובת האימייל בפועל.
מקובל להשתמש בעמודה DATA15 לאחסון נתונים של אובייקטים בינאריים גדולים (BLOB), כמו תמונות ממוזערות.
שמות של עמודות ספציפיות לסוג
כדי להקל על העבודה עם העמודות של סוג מסוים של שורה, ניהול אנשי הקשר מספק גם קבועים של שמות עמודות ספציפיים לסוג, שמוגדרים במחלקות משנה של ContactsContract.CommonDataKinds. הקבועים פשוט נותנים שם קבוע אחר לאותו שם עמודה, מה שעוזר לגשת לנתונים בשורה מסוג מסוים.
לדוגמה, המחלקה ContactsContract.CommonDataKinds.Email מגדירה קבועים של שמות עמודות ספציפיים לסוג עבור שורה של ContactsContract.Data עם סוג ה-MIME Email.CONTENT_ITEM_TYPE. הכיתה מכילה את הקבוע ADDRESS לעמודה של כתובת האימייל. הערך בפועל של ADDRESS הוא "data1", שזהה לשם הגנרי של העמודה.
זהירות: אל תוסיפו נתונים מותאמים אישית משלכם לטבלה ContactsContract.Data באמצעות שורה שיש בה אחד מסוגי ה-MIME שהוגדרו מראש על ידי הספק. אם תעשו זאת, אתם עלולים לאבד את הנתונים או לגרום לתקלה בספק. לדוגמה, אל תוסיפו שורה עם סוג ה-MIME Email.CONTENT_ITEM_TYPE שמכילה שם משתמש במקום כתובת אימייל בעמודה DATA1. אם אתם משתמשים בסוג MIME מותאם אישית משלכם לשורה, אתם יכולים להגדיר שמות עמודות ספציפיים לסוג ולהשתמש בעמודות כרצונכם.
באיור 2 אפשר לראות איך עמודות תיאור ועמודות נתונים מופיעות בשורה של ContactsContract.Data, ואיך שמות של עמודות ספציפיות לסוג "חופפים" לשמות של עמודות כלליות.
איור 2. שמות עמודות ספציפיים לסוג ושמות עמודות כלליים.
מחלקות של שמות עמודות ספציפיות לסוג
בטבלה 2 מפורטות המחלקות הנפוצות ביותר של שמות עמודות לפי סוג:
טבלה 2. מחלקות של שמות עמודות ספציפיות לסוג
| כיתת מיפוי | סוג הנתונים | הערות |
|---|---|---|
ContactsContract.CommonDataKinds.StructuredName |
נתוני השם של הנתונים הגולמיים של איש הקשר שמשויכים לשורת הנתונים הזו. | לנתונים גולמיים של איש קשר יש רק אחת מהשורות האלה. |
ContactsContract.CommonDataKinds.Photo |
התמונה הראשית של הנתונים הגולמיים של איש הקשר שמשויכים לשורת הנתונים הזו. | לנתונים גולמיים של איש קשר יש רק אחת מהשורות האלה. |
ContactsContract.CommonDataKinds.Email |
כתובת אימייל של הנתונים הגולמיים של איש הקשר שמשויכים לשורת הנתונים הזו. | לנתונים גולמיים של איש קשר יכולות להיות כמה כתובות אימייל. |
ContactsContract.CommonDataKinds.StructuredPostal |
כתובת דואר של הנתונים הגולמיים של איש הקשר שמשויכים לשורת הנתונים הזו. | לנתונים גולמיים של איש קשר יכולות להיות כמה כתובות דואר. |
ContactsContract.CommonDataKinds.GroupMembership |
מזהה שמקשר את הנתונים הגולמיים של איש הקשר לאחת מהקבוצות בניהול אנשי הקשר. | קבוצות הן תכונה אופציונלית של סוג חשבון ושם חשבון. הם מתוארים בפירוט בקטע קבוצות של אנשי קשר. |
אנשי קשר
ניהול אנשי הקשר משלב את השורות של הנתונים הגולמיים של אנשי הקשר בכל סוגי החשבונות ושמות החשבונות כדי ליצור איש קשר. כך אפשר להציג ולשנות את כל הנתונים שהמשתמש אסף על אדם מסוים. ניהול אנשי הקשר מנהל את היצירה של שורות חדשות של אנשי קשר, ואת האיסוף של נתונים גולמיים של אנשי קשר עם שורה קיימת של איש קשר. לאפליקציות ולמתאמי סנכרון אסור להוסיף אנשי קשר, וחלק מהעמודות בשורה של איש קשר הן לקריאה בלבד.
הערה: אם תנסו להוסיף איש קשר לניהול אנשי הקשר עם insert(), תקבלו חריגה מסוג UnsupportedOperationException. אם תנסו לעדכן עמודה שמוגדרת כ"לקריאה בלבד", המערכת תתעלם מהעדכון.
הספק של אנשי הקשר יוצר איש קשר חדש בתגובה להוספה של נתונים גולמיים של איש קשר חדש שלא תואמים לאף אחד מאנשי הקשר הקיימים. הספק עושה זאת גם אם הנתונים של איש קשר גולמי קיים משתנים באופן שבו הם כבר לא תואמים לאיש הקשר שאליו הם צורפו בעבר. אם אפליקציה או מתאם סנכרון יוצרים נתונים גולמיים חדשים של איש קשר שתואמים לאיש קשר קיים, הנתונים הגולמיים החדשים של איש הקשר מצטברים לאיש הקשר הקיים.
ניהול אנשי הקשר מקשר בין שורה של איש קשר לשורות של הנתונים הגולמיים של איש הקשר באמצעות העמודה _ID של שורת איש הקשר בטבלה Contacts. העמודה CONTACT_ID בטבלת הנתונים הגולמיים של אנשי הקשר
ContactsContract.RawContacts מכילה ערכי _ID עבור
שורת אנשי הקשר שמשויכת לכל שורה של נתונים גולמיים של אנשי קשר.
בטבלה ContactsContract.Contacts יש גם את העמודה LOOKUP_KEY, שהיא קישור "קבוע" לשורת איש הקשר. מכיוון שניהול אנשי הקשר מתחזק את אנשי הקשר באופן אוטומטי, הוא עשוי לשנות את הערך _ID של שורת איש קשר בתגובה לצבירה או לסנכרון. גם אם זה קורה, ה-URI של התוכן
CONTENT_LOOKUP_URI בשילוב עם
LOOKUP_KEY של איש הקשר עדיין
יפנה לשורה של איש הקשר, כך שאפשר להשתמש ב-
LOOKUP_KEY
כדי לשמור קישורים לאנשי קשר "מועדפים " וכו'. לעמודה הזו יש פורמט משלה שלא קשור לפורמט של העמודה _ID.
באיור 3 מוצג הקשר בין שלוש הטבלאות העיקריות.
איור 3. הקשרים בין הטבלאות "אנשי קשר", "נתונים גולמיים של אנשי קשר" ו"פרטים".
זהירות: אם אתם מפרסמים את האפליקציה בחנות Google Play, או אם האפליקציה שלכם נמצאת במכשיר עם Android 10 (רמת API 29) ומעלה, חשוב לזכור שקבוצה מוגבלת של שדות נתונים ושיטות של אנשי קשר כבר לא בשימוש.
בתנאים שצוינו, המערכת מנקה מדי פעם את כל הערכים שנכתבו בשדות הנתונים האלה:
-
ContactsContract.ContactOptionsColumns.LAST_TIME_CONTACTED -
ContactsContract.ContactOptionsColumns.TIMES_CONTACTED -
ContactsContract.DataUsageStatColumns.LAST_TIME_USED -
ContactsContract.DataUsageStatColumns.TIMES_USED
גם ממשקי ה-API שמשמשים להגדרת שדות הנתונים שלמעלה מיושנים:
בנוסף, השדות הבאים לא מחזירים יותר אנשי קשר תדירים. חשוב לדעת שחלק מהשדות האלה משפיעים על הדירוג של אנשי הקשר רק אם אנשי הקשר הם חלק מסוג נתונים ספציפי.
-
ContactsContract.Contacts.CONTENT_FREQUENT_URI -
ContactsContract.Contacts.CONTENT_STREQUENT_URI -
ContactsContract.Contacts.CONTENT_STREQUENT_FILTER_URI -
CONTENT_FILTER_URI(משפיע רק על סוגי הנתונים אימייל, טלפון, ניתן להתקשרות, ו- ניתן ליצירת קשר ) -
ENTERPRISE_CONTENT_FILTER_URI(משפיע רק על סוגי הנתונים אימייל, טלפון וניתן להתקשרות)
אם האפליקציות שלכם ניגשות לשדות או לממשקי ה-API האלה או מעדכנות אותם, השתמשו בשיטות חלופיות. לדוגמה, אפשר למלא תרחישי שימוש מסוימים באמצעות ספקים לניהול גישה פרטיים או נתונים אחרים שמאוחסנים באפליקציה או במערכות לקצה העורפי.
כדי לוודא שהפונקציונליות של האפליקציה לא מושפעת מהשינוי הזה, אפשר לנקות את שדות הנתונים האלה באופן ידני. כדי לעשות את זה, מריצים את פקודת ה-ADB הבאה במכשיר עם Android בגרסה 4.1 (רמת API 16) ומעלה:
adb shell content delete \ --uri content://com.android.contacts/contacts/delete_usage
נתונים ממתאמי סנכרון
המשתמשים מזינים את נתוני אנשי הקשר ישירות במכשיר, אבל הנתונים גם מועברים לניהול אנשי הקשר משירותי אינטרנט באמצעות מתאמי סנכרון, שהופכים את העברת הנתונים בין המכשיר לשירותים לאוטומטית. מתאמי סנכרון פועלים ברקע
בשליטת המערכת, והם קוראים לשיטות של ContentResolver
כדי לנהל נתונים.
ב-Android, שירות האינטרנט שמתאם הסנכרון פועל איתו מזוהה לפי סוג החשבון. כל מתאם סנכרון פועל עם סוג חשבון אחד, אבל הוא יכול לתמוך בכמה שמות של חשבונות מאותו סוג. סוגי החשבונות ושמות החשבונות מתוארים בקצרה בקטע מקורות של נתונים גולמיים של אנשי קשר. ההגדרות הבאות מספקות פרטים נוספים ומתארות איך סוג החשבון והשם שלו קשורים למתאמי סנכרון ולשירותים.
- סוג חשבון
-
מזהה שירות שבו המשתמש שמר נתונים. ברוב המקרים, המשתמש צריך לבצע אימות מול השירות. לדוגמה, אנשי קשר מחשבון Google הוא סוג חשבון שמזוהה באמצעות הקוד
google.com. הערך הזה תואם לסוג החשבון שמשמש אתAccountManager. - שם החשבון
- מזהה חשבון או פרטי התחברות מסוימים לסוג חשבון. חשבונות של אנשי קשר מחשבון Google זהים לחשבונות Google, שבהם כתובת האימייל היא שם החשבון. בשירותים אחרים, שם המשתמש יכול להיות מילה אחת או מזהה מספרי.
סוגי החשבונות לא חייבים להיות ייחודיים. משתמש יכול להגדיר כמה חשבונות של אנשי קשר בחשבון Google ולהוריד את הנתונים שלהם לניהול אנשי הקשר. זה יכול לקרות אם למשתמש יש קבוצה אחת של אנשי קשר אישיים בשם של חשבון אישי, וקבוצה אחרת לעבודה. בדרך כלל שמות החשבונות הם ייחודיים. ביחד, הם מזהים זרימת נתונים ספציפית בין ניהול אנשי הקשר לבין שירות חיצוני.
אם אתם רוצים להעביר את נתוני השירות שלכם לניהול אנשי הקשר, אתם צריכים לכתוב מתאם סנכרון משלכם. הנושא הזה מתואר בפירוט בקטע מתאמי סנכרון של ניהול אנשי הקשר.
באיור 4 מוצג איך ניהול אנשי הקשר משתלב בזרימת הנתונים על אנשים. בתיבה "מתאמי סנכרון", כל מתאם מסומן לפי סוג החשבון שלו.
איור 4. זרימת הנתונים של ניהול אנשי הקשר.
ההרשאות הנדרשות
אפליקציות שרוצות לגשת לניהול אנשי הקשר צריכות לבקש את ההרשאות הבאות:
- גישת קריאה לטבלה אחת או יותר
-
READ_CONTACTS, שצוין ב-AndroidManifest.xmlעם הרכיב<uses-permission>בתור<uses-permission android:name="android.permission.READ_CONTACTS">. - גישת כתיבה לטבלה אחת או יותר
-
WRITE_CONTACTS, שצוין ב-AndroidManifest.xmlעם הרכיב<uses-permission>בתור<uses-permission android:name="android.permission.WRITE_CONTACTS">.
ההרשאות האלה לא חלות על נתוני פרופיל המשתמש. בקטע הבא, פרופיל המשתמש, נדון בפרופיל המשתמש ובהרשאות הנדרשות שלו.
חשוב לזכור שנתוני אנשי הקשר של המשתמשים הם אישיים ורגישים. המשתמשים מודאגים לגבי הפרטיות שלהם, ולכן הם לא רוצים שאפליקציות יאספו נתונים עליהם או על אנשי הקשר שלהם. אם לא ברור למה אתם צריכים הרשאה לגשת לנתוני אנשי הקשר, יכול להיות שהמשתמשים יתנו לאפליקציה דירוגים נמוכים או פשוט יסרבו להתקין אותה.
פרופיל המשתמש
בטבלה ContactsContract.Contacts יש שורה אחת שמכילה את נתוני הפרופיל של המשתמש במכשיר. הנתונים האלה מתארים את user של המכשיר, ולא את אחד מאנשי הקשר של המשתמש. השורה של פרופיל אנשי הקשר מקושרת לשורה של נתונים גולמיים של אנשי קשר בכל מערכת שמשתמשת בפרופיל.
לכל שורה של נתונים גולמיים של איש קשר בפרופיל יכולות להיות כמה שורות נתונים. קבועים לגישה לפרופיל המשתמש זמינים במחלקה ContactsContract.Profile.
כדי לגשת לפרופיל המשתמש נדרשות הרשאות מיוחדות. בנוסף להרשאות READ_CONTACTS ו-WRITE_CONTACTS שנדרשות לקריאה ולכתיבה, כדי לגשת לפרופיל המשתמש נדרשות ההרשאות android.Manifest.permission#READ_PROFILE ו-android.Manifest.permission#WRITE_PROFILE לגישת קריאה וכתיבה, בהתאמה.
חשוב לזכור שפרופיל של משתמש נחשב למידע רגיש. ההרשאה android.Manifest.permission#READ_PROFILE מאפשרת לכם לגשת לפרטים האישיים המזהים של המשתמש במכשיר. חשוב להסביר למשתמשים למה אתם צריכים הרשאות גישה לפרופיל המשתמש בתיאור של האפליקציה.
כדי לאחזר את שורת איש הקשר שמכילה את פרופיל המשתמש, מפעילים את ContentResolver.query(). מגדירים את ה-URI של התוכן לערך
CONTENT_URI ולא מספקים
קריטריונים לבחירה. אפשר גם להשתמש ב-URI של התוכן הזה בתור ה-URI הבסיסי לאחזור נתונים גולמיים של אנשי קשר או נתונים לפרופיל. לדוגמה, קטע הקוד הזה מאחזר נתונים מהפרופיל:
Kotlin
// Sets the columns to retrieve for the user profile projection = arrayOf( ContactsContract.Profile._ID, ContactsContract.Profile.DISPLAY_NAME_PRIMARY, ContactsContract.Profile.LOOKUP_KEY, ContactsContract.Profile.PHOTO_THUMBNAIL_URI ) // Retrieves the profile from the Contacts Provider profileCursor = contentResolver.query( ContactsContract.Profile.CONTENT_URI, projection, null, null, null )
Java
// Sets the columns to retrieve for the user profile projection = new String[] { Profile._ID, Profile.DISPLAY_NAME_PRIMARY, Profile.LOOKUP_KEY, Profile.PHOTO_THUMBNAIL_URI }; // Retrieves the profile from the Contacts Provider profileCursor = getContentResolver().query( Profile.CONTENT_URI, projection , null, null, null);
הערה: אם אתם מאחזרים כמה שורות של אנשי קשר, ואתם רוצים לקבוע אם אחת מהן היא פרופיל המשתמש, בדקו את העמודה IS_USER_PROFILE של השורה. הערך בעמודה הזו מוגדר כ-"1" אם איש הקשר הוא פרופיל המשתמש.
מטא-נתונים של ניהול אנשי הקשר
הספק של אנשי הקשר מנהל את הנתונים שעוקבים אחרי המצב של נתוני אנשי הקשר במאגר. המטא-נתונים האלה על המאגר מאוחסנים במקומות שונים, כולל בשורות הטבלה של הנתונים הגולמיים של אנשי הקשר, הנתונים ואנשי הקשר, בטבלה ContactsContract.Settings ובטבלה ContactsContract.SyncState. בטבלה הבאה מוצגת ההשפעה של כל אחד מהמטא-נתונים האלה:
טבלה 3. מטא-נתונים בניהול אנשי הקשר
| טבלה | עמודה | ערכים | משמעות |
|---|---|---|---|
ContactsContract.RawContacts |
DIRTY |
"0" – לא השתנה מאז הסנכרון האחרון. |
מסמן נתונים גולמיים של אנשי קשר שהשתנו במכשיר וצריך לסנכרן אותם בחזרה
לשרת. הערך מוגדר באופן אוטומטי על ידי ניהול אנשי הקשר כשאפליקציות ל-Android מעדכנות שורה.
מתאמי סנכרון שמשנים את הנתונים הגולמיים של איש הקשר או את טבלאות הנתונים צריכים תמיד להוסיף את המחרוזת |
| "1" – השתנה מאז הסנכרון האחרון, צריך לסנכרן בחזרה לשרת. | |||
ContactsContract.RawContacts |
VERSION |
מספר הגרסה של השורה הזו. | ניהול אנשי הקשר מגדיל את הערך הזה באופן אוטומטי בכל פעם שהשורה או הנתונים שקשורים אליה משתנים. |
ContactsContract.Data |
DATA_VERSION |
מספר הגרסה של השורה הזו. | ניהול אנשי הקשר מגדיל את הערך הזה באופן אוטומטי בכל פעם ששורת הנתונים משתנה. |
ContactsContract.RawContacts |
SOURCE_ID |
ערך מחרוזת שמזהה באופן ייחודי את הנתונים הגולמיים של איש הקשר בחשבון שבו הם נוצרו. |
כשמתאם סנכרון יוצר נתונים גולמיים חדשים של איש קשר, צריך להגדיר בעמודה הזו את המזהה הייחודי של השרת לנתונים הגולמיים של איש הקשר. כשאפליקציה ל-Android יוצרת נתונים גולמיים חדשים של איש קשר, היא צריכה להשאיר את העמודה הזו ריקה. כך מתאם הסנכרון מקבל איתות ליצור נתונים גולמיים חדשים של איש קשר בשרת, ולקבל ערך ל-SOURCE_ID.
במיוחד, מזהה המקור חייב להיות ייחודי לכל סוג חשבון וצריך להיות יציב בין סנכרונים:
|
ContactsContract.Groups |
GROUP_VISIBLE |
"0" – אנשי הקשר בקבוצה הזו לא אמורים להופיע בממשקי המשתמש של אפליקציות ל-Android. | העמודה הזו נועדה לתאימות עם שרתים שמאפשרים למשתמש להסתיר אנשי קשר בקבוצות מסוימות. |
| "1" – אנשי הקשר בקבוצה הזו יכולים להופיע בממשקי המשתמש של האפליקציה. | |||
ContactsContract.Settings |
UNGROUPED_VISIBLE |
"0" – בחשבון הזה ובסוג החשבון הזה, אנשי קשר שלא שייכים לקבוצה לא גלויים לממשקי משתמש של אפליקציות ל-Android. |
כברירת מחדל, אנשי הקשר לא גלויים אם אף אחד מהנתונים הגולמיים של אנשי הקשר לא שייך לקבוצה
(החברות בקבוצה של נתונים גולמיים של איש קשר מצוינת על ידי שורה אחת או יותר של
ContactsContract.CommonDataKinds.GroupMembership
בטבלה ContactsContract.Data).
אם מגדירים את הדגל הזה בשורת הטבלה ContactsContract.Settings
לסוג חשבון ולחשבון, אפשר לאלץ את הצגת אנשי הקשר ללא קבוצות.
אחד מהשימושים של הדגל הזה הוא להציג אנשי קשר משרתים שלא משתמשים בקבוצות.
|
| "1" – בחשבון הזה ובסוג החשבון הזה, אנשי קשר שלא שייכים לקבוצה גלויים לממשקי משתמש של אפליקציות. | |||
ContactsContract.SyncState |
(הכול) | בטבלה הזו אפשר לאחסן מטא-נתונים של מתאם הסנכרון. | בעזרת הטבלה הזו אפשר לאחסן את מצב הסנכרון ונתונים אחרים שקשורים לסנכרון באופן קבוע במכשיר. |
גישה לניהול אנשי הקשר
בקטע הזה מוסברות ההנחיות לגישה לנתונים מניהול אנשי הקשר, תוך התמקדות בנושאים הבאים:
- שאילתות לגבי ישויות.
- שינוי אצווה
- אחזור ושינוי באמצעות כוונות.
- תקינות הנתונים.
בקטע מתאמי סנכרון של ניהול אנשי הקשר מוסבר בפירוט איך לבצע שינויים באמצעות מתאם סנכרון.
שליחת שאילתות לגבי ישויות
מכיוון שהטבלאות של ניהול אנשי הקשר מאורגנות בהיררכיה, לעיתים קרובות כדאי לאחזר שורה ואת כל שורות ה"צאצא" שמקושרות אליה. לדוגמה, כדי להציג את כל המידע על אדם מסוים, יכול להיות שתרצו לאחזר את כל השורות של ContactsContract.RawContacts בשביל שורה אחת של ContactsContract.Contacts, או את כל השורות של ContactsContract.CommonDataKinds.Email בשביל שורה אחת של ContactsContract.RawContacts. כדי לאפשר את זה, ספק אנשי הקשר מציע מבני ישות, שפועלים כמו איחודים של מסדי נתונים בין טבלאות.
ישות היא כמו טבלה שמורכבת מעמודות שנבחרו מטבלת הורה ומהטבלה המשנית שלה.
כששולחים שאילתה לישות, צריך לספק היטל וקריטריונים לחיפוש על סמך העמודות שזמינות בישות. התוצאה היא Cursor שמכיל שורה אחת לכל שורה בטבלת הצאצא שאוחזרה. לדוגמה, אם שולחים שאילתה ל-ContactsContract.Contacts.Entity לגבי שם של איש קשר וכל השורות של ContactsContract.CommonDataKinds.Email לגבי כל הנתונים הגולמיים של אנשי הקשר עם השם הזה, מקבלים בחזרה Cursor שמכיל שורה אחת לכל שורה של ContactsContract.CommonDataKinds.Email.
ישויות מפשטות את השאילתות. באמצעות ישות, אתם יכולים לאחזר את כל נתוני אנשי הקשר של איש קשר או נתונים גולמיים של איש קשר בבת אחת, במקום לבצע קודם שאילתה בטבלת ההורה כדי לקבל מזהה, ואז לבצע שאילתה בטבלת הצאצא עם המזהה הזה. בנוסף, ניהול אנשי הקשר מעבד שאילתה מול ישות בעסקה אחת, וכך מבטיח שהנתונים שאוחזרו עקביים באופן פנימי.
הערה: בדרך כלל ישות לא מכילה את כל העמודות של טבלת ההורה וטבלת הצאצא. אם תנסו לעבוד עם שם עמודה שלא נמצא ברשימת הקבועים של שמות העמודות של הישות, תקבלו Exception.
בקטע הקוד הבא אפשר לראות איך לאחזר את כל השורות של הנתונים הגולמיים של איש קשר מסוים. קטע הקוד הוא חלק מאפליקציה גדולה יותר שיש בה שתי פעילויות, "main" ו-"detail". הפעילות הראשית מציגה רשימה של שורות אנשי קשר. כשהמשתמש בוחר אחת מהן, הפעילות שולחת את המזהה שלה לפעילות הפרטים. הפעילות של הפרטים משתמשת ב-ContactsContract.Contacts.Entity
כדי להציג את כל שורות הנתונים מכל הנתונים הגולמיים של אנשי הקשר שמשויכים לאיש הקשר
שנבחר.
קטע הקוד הזה נלקח מהפעילות "detail":
Kotlin
... /* * Appends the entity path to the URI. In the case of the Contacts Provider, the * expected URI is content://com.google.contacts/#/entity (# is the ID value). */ contactUri = Uri.withAppendedPath( contactUri, ContactsContract.Contacts.Entity.CONTENT_DIRECTORY ) // Initializes the loader identified by LOADER_ID. loaderManager.initLoader( LOADER_ID, // The identifier of the loader to initialize null, // Arguments for the loader (in this case, none) this // The context of the activity ) // Creates a new cursor adapter to attach to the list view cursorAdapter = SimpleCursorAdapter( this, // the context of the activity R.layout.detail_list_item, // the view item containing the detail widgets mCursor, // the backing cursor fromColumns, // the columns in the cursor that provide the data toViews, // the views in the view item that display the data 0) // flags // Sets the ListView's backing adapter. rawContactList.adapter = cursorAdapter ... override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { /* * Sets the columns to retrieve. * RAW_CONTACT_ID is included to identify the raw contact associated with the data row. * DATA1 contains the first column in the data row (usually the most important one). * MIMETYPE indicates the type of data in the data row. */ val projection: Array<String> = arrayOf( ContactsContract.Contacts.Entity.RAW_CONTACT_ID, ContactsContract.Contacts.Entity.DATA1, ContactsContract.Contacts.Entity.MIMETYPE ) /* * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw * contact collated together. */ val sortOrder = "${ContactsContract.Contacts.Entity.RAW_CONTACT_ID} ASC" /* * Returns a new CursorLoader. The arguments are similar to * ContentResolver.query(), except for the Context argument, which supplies the location of * the ContentResolver to use. */ return CursorLoader( applicationContext, // The activity's context contactUri, // The entity content URI for a single contact projection, // The columns to retrieve null, // Retrieve all the raw contacts and their data rows. null, // sortOrder // Sort by the raw contact ID. ) }
Java
... /* * Appends the entity path to the URI. In the case of the Contacts Provider, the * expected URI is content://com.google.contacts/#/entity (# is the ID value). */ contactUri = Uri.withAppendedPath( contactUri, ContactsContract.Contacts.Entity.CONTENT_DIRECTORY); // Initializes the loader identified by LOADER_ID. getLoaderManager().initLoader( LOADER_ID, // The identifier of the loader to initialize null, // Arguments for the loader (in this case, none) this); // The context of the activity // Creates a new cursor adapter to attach to the list view cursorAdapter = new SimpleCursorAdapter( this, // the context of the activity R.layout.detail_list_item, // the view item containing the detail widgets mCursor, // the backing cursor fromColumns, // the columns in the cursor that provide the data toViews, // the views in the view item that display the data 0); // flags // Sets the ListView's backing adapter. rawContactList.setAdapter(cursorAdapter); ... @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { /* * Sets the columns to retrieve. * RAW_CONTACT_ID is included to identify the raw contact associated with the data row. * DATA1 contains the first column in the data row (usually the most important one). * MIMETYPE indicates the type of data in the data row. */ String[] projection = { ContactsContract.Contacts.Entity.RAW_CONTACT_ID, ContactsContract.Contacts.Entity.DATA1, ContactsContract.Contacts.Entity.MIMETYPE }; /* * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw * contact collated together. */ String sortOrder = ContactsContract.Contacts.Entity.RAW_CONTACT_ID + " ASC"; /* * Returns a new CursorLoader. The arguments are similar to * ContentResolver.query(), except for the Context argument, which supplies the location of * the ContentResolver to use. */ return new CursorLoader( getApplicationContext(), // The activity's context contactUri, // The entity content URI for a single contact projection, // The columns to retrieve null, // Retrieve all the raw contacts and their data rows. null, // sortOrder); // Sort by the raw contact ID. }
בסיום הטעינה, LoaderManager מפעיל קריאה חוזרת (callback) אל onLoadFinished(). אחד מהארגומנטים הנכנסים ל-method הזו הוא Cursor עם תוצאות השאילתה. באפליקציה שלכם, אתם יכולים לקבל את הנתונים מה-Cursor הזה כדי להציג אותם או להמשיך לעבוד איתם.
שינוי באצווה
בכל פעם שאפשר, כדאי להוסיף, לעדכן ולמחוק נתונים בניהול אנשי הקשר ב"מצב אצווה". כדי לעשות את זה, יוצרים ArrayList של אובייקטים מסוג ContentProviderOperation וקוראים ל-applyBatch(). מכיוון שניהול אנשי הקשר מבצע את כל הפעולות ב-applyBatch() בעסקה אחת, השינויים אף פעם לא ישאירו את מאגר אנשי הקשר במצב לא עקבי. שינוי באצווה גם מאפשר להוסיף נתונים גולמיים של איש קשר ואת הנתונים המפורטים שלו בו-זמנית.
הערה: כדי לשנות נתונים גולמיים של איש קשר אחד, כדאי לשלוח Intent לאפליקציה לניהול אנשי הקשר במכשיר במקום לטפל בשינוי באפליקציה שלכם. הפעולה הזו מתוארת בפירוט רב יותר בקטע אחזור ושינוי באמצעות Intent.
נקודות עצירה
שינוי באצווה שמכיל מספר גדול של פעולות יכול לחסום תהליכים אחרים, וכתוצאה מכך לפגוע בחוויית המשתמש הכוללת. כדי לארגן את כל השינויים שאתם רוצים לבצע בכמה שפחות רשימות נפרדות, ובמקביל למנוע מהם לחסום את המערכת, כדאי להגדיר נקודות עצירה לפעולה אחת או יותר.
נקודת עצירה היא אובייקט ContentProviderOperation שהערך של isYieldAllowed() שלו מוגדר כ-true. כאשר ניהול אנשי הקשר נתקל בנקודת עצירה, הוא משהה את העבודה שלו כדי לאפשר לתהליכים אחרים לפעול, וסוגר את הטרנזקציה הנוכחית. כשהספק מתחיל שוב, הוא ממשיך עם הפעולה הבאה ב-ArrayList ומתחיל טרנזקציה חדשה.
נקודות עצירה גורמות ליותר מעסקה אחת לכל קריאה אל applyBatch(). לכן, כדאי להגדיר נקודת עצירה לפעולה האחרונה בקבוצה של שורות קשורות.
לדוגמה, כדאי להגדיר נקודת עצירה לפעולה האחרונה בקבוצה שמוסיפה שורות של נתונים גולמיים של איש קשר ואת שורות הנתונים שמשויכות אליהן, או לפעולה האחרונה בקבוצה של שורות שקשורות לאיש קשר אחד.
נקודות עצירה הן גם יחידה של פעולה אטומית. כל הגישות בין שתי נקודות עצירה יצליחו או ייכשלו כיחידה אחת. אם לא מגדירים נקודות עצירה, הפעולה האטומית הקטנה ביותר היא כל קבוצת הפעולות. אם משתמשים בנקודות עצירה, מונעים מהפעולות לפגוע בביצועי המערכת, ובו-זמנית מבטיחים שקבוצת משנה של פעולות תהיה אטומית.
הפניות חזרה לשינויים
כשמוסיפים שורה חדשה של נתונים גולמיים של איש קשר ואת שורות הנתונים שמשויכות אליה כקבוצה של אובייקטים מסוג ContentProviderOperation, צריך לקשר את שורות הנתונים לשורה של הנתונים הגולמיים של איש הקשר. כדי לעשות את זה, מוסיפים את הערך _ID של הנתונים הגולמיים של איש הקשר כערך RAW_CONTACT_ID. עם זאת, הערך הזה לא זמין כשיוצרים את ContentProviderOperation לשורת הנתונים, כי עדיין לא החלתם את ContentProviderOperation על השורה של הנתונים הגולמיים של איש הקשר. כדי לעקוף את הבעיה,
למחלקה ContentProviderOperation.Builder יש את השיטה
withValueBackReference().
השיטה הזו מאפשרת להוסיף או לשנות עמודה עם התוצאה של פעולה קודמת.
לשיטה withValueBackReference() יש שני ארגומנטים:
-
key - המפתח של צמד מפתח/ערך. הערך של הארגומנט הזה צריך להיות שם של עמודה בטבלה שאתם משנים.
-
previousResult -
האינדקס שמתחיל בספרה אפס של ערך במערך של אובייקטים מסוג
ContentProviderResultמ-applyBatch(). בזמן שהפעולות באצווה מופעלות, התוצאה של כל פעולה נשמרת במערך תוצאות ביניים. הערךpreviousResultהוא האינדקס של אחת מהתוצאות האלה, שמאוחזר ומאוחסן עם הערךkey. כך אפשר להוסיף רשומה חדשה של נתונים גולמיים של איש קשר, לקבל בחזרה את הערך של_ID, ואז ליצור "הפניה לאחור" לערך כשמוסיפים שורה שלContactsContract.Data.מערך התוצאות כולו נוצר כשקוראים ל-
applyBatch()בפעם הראשונה, והגודל שלו שווה לגודל שלArrayListאובייקטים מסוגContentProviderOperationשאתם מספקים. עם זאת, כל הרכיבים במערך התוצאות מוגדרים כ-null, ואם מנסים להפנות חזרה לתוצאה של פעולה שעדיין לא בוצעה,withValueBackReference()מחזירException.
בקטעי הקוד הבאים אפשר לראות איך להוסיף נתונים גולמיים חדשים של איש קשר ונתונים באצווה. הם כוללים קוד שמגדיר נקודת עצירה ומשתמש בהפניה לאחור.
קטע הקוד הראשון מאחזר את נתוני איש הקשר מממשק המשתמש. בשלב הזה, המשתמש כבר בחר את החשבון שאליו צריך להוסיף את הנתונים הגולמיים של איש הקשר החדש.
Kotlin
// Creates a contact entry from the current UI values, using the currently-selected account. private fun createContactEntry() { /* * Gets values from the UI */ val name = contactNameEditText.text.toString() val phone = contactPhoneEditText.text.toString() val email = contactEmailEditText.text.toString() val phoneType: String = contactPhoneTypes[mContactPhoneTypeSpinner.selectedItemPosition] val emailType: String = contactEmailTypes[mContactEmailTypeSpinner.selectedItemPosition]
Java
// Creates a contact entry from the current UI values, using the currently-selected account. protected void createContactEntry() { /* * Gets values from the UI */ String name = contactNameEditText.getText().toString(); String phone = contactPhoneEditText.getText().toString(); String email = contactEmailEditText.getText().toString(); int phoneType = contactPhoneTypes.get( contactPhoneTypeSpinner.getSelectedItemPosition()); int emailType = contactEmailTypes.get( contactEmailTypeSpinner.getSelectedItemPosition());
קטע הקוד הבא יוצר פעולה להוספת השורה של הנתונים הגולמיים של איש הקשר לטבלה ContactsContract.RawContacts:
Kotlin
/* * Prepares the batch operation for inserting a new raw contact and its data. Even if * the Contacts Provider does not have any data for this person, you can't add a Contact, * only a raw contact. The Contacts Provider will then add a Contact automatically. */ // Creates a new array of ContentProviderOperation objects. val ops = arrayListOf<ContentProviderOperation>() /* * Creates a new raw contact with its account type (server type) and account name * (user's account). Remember that the display name is not stored in this row, but in a * StructuredName data row. No other data is required. */ var op: ContentProviderOperation.Builder = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.name) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.type) // Builds the operation and adds it to the array of operations ops.add(op.build())
Java
/* * Prepares the batch operation for inserting a new raw contact and its data. Even if * the Contacts Provider does not have any data for this person, you can't add a Contact, * only a raw contact. The Contacts Provider will then add a Contact automatically. */ // Creates a new array of ContentProviderOperation objects. ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); /* * Creates a new raw contact with its account type (server type) and account name * (user's account). Remember that the display name is not stored in this row, but in a * StructuredName data row. No other data is required. */ ContentProviderOperation.Builder op = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.getType()) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.getName()); // Builds the operation and adds it to the array of operations ops.add(op.build());
לאחר מכן, הקוד יוצר שורות נתונים לשם המוצג, למספר הטלפון ולכתובת האימייל.
כל אובייקט של בניית פעולה משתמש ב-withValueBackReference() כדי לקבל את ה-RAW_CONTACT_ID. ההפניה מצביעה
חזרה לאובייקט ContentProviderResult מהפעולה הראשונה,
שמוסיפה את השורה של הנתונים הגולמיים של איש הקשר ומחזירה את הערך החדש של _ID. כתוצאה מכך, כל שורת נתונים מקושרת באופן אוטומטי באמצעות RAW_CONTACT_ID לשורת ContactsContract.RawContacts החדשה שאליה היא שייכת.
האובייקט ContentProviderOperation.Builder שמוסיף את שורת האימייל מסומן ב-withYieldAllowed(), שמגדיר נקודת עצירה:
Kotlin
// Creates the display name for the new raw contact, as a StructuredName data row. op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * withValueBackReference sets the value of the first argument to the value of * the ContentProviderResult indexed by the second argument. In this particular * call, the raw contact ID column of the StructuredName data row is set to the * value of the result returned by the first operation, which is the one that * actually adds the raw contact row. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to StructuredName .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) // Sets the data row's display name to the name in the UI. .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name) // Builds the operation and adds it to the array of operations ops.add(op.build()) // Inserts the specified phone number and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Phone .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Sets the phone number and type .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType) // Builds the operation and adds it to the array of operations ops.add(op.build()) // Inserts the specified email and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Email .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Sets the email address and type .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType) /* * Demonstrates a yield point. At the end of this insert, the batch operation's thread * will yield priority to other threads. Use after every set of operations that affect a * single contact, to avoid degrading performance. */ op.withYieldAllowed(true) // Builds the operation and adds it to the array of operations ops.add(op.build())
Java
// Creates the display name for the new raw contact, as a StructuredName data row. op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * withValueBackReference sets the value of the first argument to the value of * the ContentProviderResult indexed by the second argument. In this particular * call, the raw contact ID column of the StructuredName data row is set to the * value of the result returned by the first operation, which is the one that * actually adds the raw contact row. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to StructuredName .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) // Sets the data row's display name to the name in the UI. .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name); // Builds the operation and adds it to the array of operations ops.add(op.build()); // Inserts the specified phone number and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Phone .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Sets the phone number and type .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType); // Builds the operation and adds it to the array of operations ops.add(op.build()); // Inserts the specified email and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Email .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Sets the email address and type .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType); /* * Demonstrates a yield point. At the end of this insert, the batch operation's thread * will yield priority to other threads. Use after every set of operations that affect a * single contact, to avoid degrading performance. */ op.withYieldAllowed(true); // Builds the operation and adds it to the array of operations ops.add(op.build());
קטע הקוד האחרון מציג את הקריאה ל-applyBatch() שמכניסה את הנתונים הגולמיים החדשים של איש הקשר ואת שורות הנתונים.
Kotlin
// Ask the Contacts Provider to create a new contact Log.d(TAG, "Selected account: ${mSelectedAccount.name} (${mSelectedAccount.type})") Log.d(TAG, "Creating contact: $name") /* * Applies the array of ContentProviderOperation objects in batch. The results are * discarded. */ try { contentResolver.applyBatch(ContactsContract.AUTHORITY, ops) } catch (e: Exception) { // Display a warning val txt: String = getString(R.string.contactCreationFailure) Toast.makeText(applicationContext, txt, Toast.LENGTH_SHORT).show() // Log exception Log.e(TAG, "Exception encountered while inserting contact: $e") } }
Java
// Ask the Contacts Provider to create a new contact Log.d(TAG,"Selected account: " + selectedAccount.getName() + " (" + selectedAccount.getType() + ")"); Log.d(TAG,"Creating contact: " + name); /* * Applies the array of ContentProviderOperation objects in batch. The results are * discarded. */ try { getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); } catch (Exception e) { // Display a warning Context ctx = getApplicationContext(); CharSequence txt = getString(R.string.contactCreationFailure); int duration = Toast.LENGTH_SHORT; Toast toast = Toast.makeText(ctx, txt, duration); toast.show(); // Log exception Log.e(TAG, "Exception encountered while inserting contact: " + e); } }
פעולות באצווה גם מאפשרות להטמיע בקרת בו-זמניות אופטימית, שיטה להחלת טרנזקציות של שינויים בלי לנעול את המאגר הבסיסי. כדי להשתמש בשיטה הזו, מפעילים את הטרנזקציה ואז בודקים אם בוצעו שינויים אחרים באותו הזמן. אם אתם מזהים שינוי לא עקבי, אתם יכולים לבטל את העסקה ולנסות שוב.
בקרת בו-זמניות אופטימית שימושית במכשיר נייד, שבו יש רק משתמש אחד בכל פעם, וגישות בו-זמניות למאגר נתונים הן נדירות. מכיוון שלא נעשה שימוש בנעילה, לא מתבזבז זמן על הגדרת נעילות או על המתנה לעסקאות אחרות שישחררו את הנעילות שלהן.
כדי להשתמש בבקרת בו-זמניות אופטימית בזמן עדכון של שורה אחת ב-ContactsContract.RawContacts, פועלים לפי השלבים הבאים:
-
מאחזרים את העמודה
VERSIONשל הנתונים הגולמיים של איש הקשר, יחד עם הנתונים האחרים שמאחזרים. -
יוצרים אובייקט
ContentProviderOperation.Builderשמתאים לאכיפת אילוץ, באמצעות ה-methodnewAssertQuery(Uri). ב-URI של התוכן, משתמשים ב-RawContacts.CONTENT_URIומוסיפים לו את ה-_IDשל הנתונים הגולמיים של איש הקשר. -
באובייקט
ContentProviderOperation.Builder, מפעילים אתwithValue()כדי להשוות בין העמודהVERSIONלבין מספר הגרסה שאוחזר. -
לאותו
ContentProviderOperation.Builder, צריך להפעיל אתwithExpectedCount()כדי לוודא שרק שורה אחת נבדקת על ידי ההצהרה הזו. -
מפעילים את
build()כדי ליצור את האובייקטContentProviderOperation, ואז מוסיפים את האובייקט הזה כאובייקט הראשון ב-ArrayListשמעבירים אלapplyBatch(). - מחילים את העסקה באצווה.
אם השורה של הנתונים הגולמיים של איש הקשר מתעדכנת על ידי פעולה אחרת בין הזמן שבו קראתם את השורה לבין הזמן שבו ניסיתם לשנות אותה, ה-assert ContentProviderOperation ייכשל וכל קבוצת הפעולות תבוטל. אחר כך תוכלו לבחור אם לנסות שוב את הקבוצה או לבצע פעולה אחרת.
בקטע הקוד הבא אפשר לראות איך יוצרים "assert" של ContentProviderOperation אחרי שליחת שאילתה לגבי נתונים גולמיים של איש קשר אחד באמצעות CursorLoader:
Kotlin
/* * The application uses CursorLoader to query the raw contacts table. The system calls this method * when the load is finished. */ override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) { // Gets the raw contact's _ID and VERSION values rawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID)) mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION)) } ... // Sets up a Uri for the assert operation val rawContactUri: Uri = ContentUris.withAppendedId( ContactsContract.RawContacts.CONTENT_URI, rawContactID ) // Creates a builder for the assert operation val assertOp: ContentProviderOperation.Builder = ContentProviderOperation.newAssertQuery(rawContactUri).apply { // Adds the assertions to the assert operation: checks the version withValue(SyncColumns.VERSION, mVersion) // and count of rows tested withExpectedCount(1) } // Creates an ArrayList to hold the ContentProviderOperation objects val ops = arrayListOf<ContentProviderOperation>() ops.add(assertOp.build()) // You would add the rest of your batch operations to "ops" here ... // Applies the batch. If the assert fails, an Exception is thrown try { val results: Array<ContentProviderResult> = contentResolver.applyBatch(AUTHORITY, ops) } catch (e: OperationApplicationException) { // Actions you want to take if the assert operation fails go here }
Java
/* * The application uses CursorLoader to query the raw contacts table. The system calls this method * when the load is finished. */ public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { // Gets the raw contact's _ID and VERSION values rawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID)); mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION)); } ... // Sets up a Uri for the assert operation Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactID); // Creates a builder for the assert operation ContentProviderOperation.Builder assertOp = ContentProviderOperation.newAssertQuery(rawContactUri); // Adds the assertions to the assert operation: checks the version and count of rows tested assertOp.withValue(SyncColumns.VERSION, mVersion); assertOp.withExpectedCount(1); // Creates an ArrayList to hold the ContentProviderOperation objects ArrayList ops = new ArrayList<ContentProviderOperation>; ops.add(assertOp.build()); // You would add the rest of your batch operations to "ops" here ... // Applies the batch. If the assert fails, an Exception is thrown try { ContentProviderResult[] results = getContentResolver().applyBatch(AUTHORITY, ops); } catch (OperationApplicationException e) { // Actions you want to take if the assert operation fails go here }
אחזור ושינוי באמצעות כוונות
שליחת Intent לאפליקציה לניהול אנשי הקשר במכשיר מאפשרת לגשת לניהול אנשי הקשר באופן עקיף. ה-Intent מפעיל את ממשק המשתמש של האפליקציה לניהול אנשי הקשר במכשיר, שבו המשתמשים יכולים לבצע פעולות שקשורות לאנשי הקשר. משתמשים עם סוג הגישה הזה יכולים:
- בוחרים איש קשר מהרשימה ומחזירים אותו לאפליקציה כדי להמשיך לעבוד איתו.
- לערוך את הנתונים של איש קשר קיים.
- להוסיף נתונים גולמיים של איש קשר חדש לכל אחד מהחשבונות שלהם.
- למחוק איש קשר או נתונים של אנשי קשר.
אם המשתמש מוסיף או מעדכן נתונים, אפשר לאסוף את הנתונים קודם ולשלוח אותם כחלק מה-Intent.
כשמשתמשים ב-Intent כדי לגשת לניהול אנשי הקשר דרך האפליקציה לניהול אנשי הקשר במכשיר, לא צריך לכתוב ממשק משתמש או קוד משלכם כדי לגשת לספק. אתם גם לא צריכים לבקש הרשאה לקרוא מהספק או לכתוב אליו. האפליקציה לניהול אנשי הקשר במכשיר יכולה להעניק לכם הרשאת קריאה לאיש קשר, ומכיוון שאתם מבצעים שינויים בספק דרך אפליקציה אחרת, אתם לא צריכים הרשאות כתיבה.
התהליך הכללי של שליחת Intent כדי לגשת לספק מתואר בפירוט במדריך
היסודות של ספק לניהול גישה בקטע "גישה לנתונים באמצעות Intent". הפעולה, סוג ה-MIME וערכי הנתונים שבהם משתמשים למשימות הזמינות מסוכמים בטבלה 4, וערכי התוספות שאפשר להשתמש בהם עם putExtra() מפורטים במאמרי העזרה של ContactsContract.Intents.Insert:
טבלה 4. כוונות של ניהול אנשי הקשר.
| משימה | פעולה | נתונים | סוג MIME | הערות |
|---|---|---|---|---|
| בחירת איש קשר מהרשימה | ACTION_PICK |
אחת מהאפשרויות:
|
לא בשימוש |
הצגת רשימה של נתונים גולמיים של אנשי קשר או רשימה של נתונים מאיש קשר גולמי, בהתאם לסוג ה-URI של התוכן שסיפקתם.
מפעילים את
|
| הוספת נתונים גולמיים של איש קשר חדש | Insert.ACTION |
לא רלוונטי |
RawContacts.CONTENT_TYPE, סוג MIME לקבוצה של נתונים גולמיים של אנשי קשר.
|
הצגת המסך הוספת איש קשר באפליקציה לניהול אנשי הקשר במכשיר. ערכי ה-extras שמוסיפים ל-intent מוצגים. אם נשלח עם
startActivityForResult(),
ה-URI של התוכן של הנתונים הגולמיים של איש הקשר שנוסף מועבר בחזרה לשיטת הקריאה החוזרת (callback)
onActivityResult()
של הפעילות בארגומנט Intent, בשדה
"data". כדי לקבל את הערך, צריך להפעיל את getData().
|
| עריכה של איש קשר | ACTION_EDIT |
CONTENT_LOOKUP_URI של איש הקשר. פעילות העריכה תאפשר למשתמש לערוך את כל הנתונים שמשויכים לאיש הקשר הזה.
|
Contacts.CONTENT_ITEM_TYPE, איש קשר אחד. |
הצגת המסך "עריכת איש הקשר" באפליקציה לניהול אנשי הקשר. ערכי התוספות שמוסיפים ל-intent מוצגים. כשהמשתמש לוחץ על Done כדי לשמור את השינויים, הפעילות חוזרת לחזית. |
| הצגת בורר שגם יכול להוסיף נתונים. | ACTION_INSERT_OR_EDIT |
לא רלוונטי |
CONTENT_ITEM_TYPE
|
הכוונה הזו תמיד מציגה את מסך הבחירה של אפליקציית אנשי הקשר. המשתמש יכול לבחור איש קשר לעריכה או להוסיף איש קשר חדש. מסך העריכה או מסך ההוספה מופיע, בהתאם לבחירת המשתמש, ומוצגים נתוני התוספות שאתם מעבירים ב-Intent. אם האפליקציה מציגה פרטים ליצירת קשר כמו כתובת אימייל או מספר טלפון, אפשר להשתמש ב-Intent הזה כדי לאפשר למשתמש להוסיף את הפרטים לאיש קשר קיים.
איש קשר,
הערה: אין צורך לשלוח ערך של שם בתוספות של ה-Intent הזה, כי המשתמש תמיד בוחר שם קיים או מוסיף שם חדש. בנוסף, אם תשלחו שם והמשתמש יבחר לערוך אותו, אפליקציית אנשי הקשר תציג את השם ששלחתם ותחליף את הערך הקודם. אם המשתמש לא שם לב לכך ושומר את העריכה, הערך הישן אובד. |
אפליקציית אנשי הקשר של המכשיר לא מאפשרת למחוק נתונים גולמיים של איש קשר או כל אחד מהנתונים שלו באמצעות Intent. כדי למחוק נתונים גולמיים של איש קשר, צריך להשתמש ב-ContentResolver.delete() או ב-ContentProviderOperation.newDelete().
בקטע הקוד הבא אפשר לראות איך יוצרים ושולחים Intent שמוסיף נתונים גולמיים חדשים של איש קשר ונתונים:
Kotlin
// Gets values from the UI val name = contactNameEditText.text.toString() val phone = contactPhoneEditText.text.toString() val email = contactEmailEditText.text.toString() val company = companyName.text.toString() val jobtitle = jobTitle.text.toString() /* * Demonstrates adding data rows as an array list associated with the DATA key */ // Defines an array list to contain the ContentValues objects for each row val contactData = arrayListOf<ContentValues>() /* * Defines the raw contact row */ // Sets up the row as a ContentValues object val rawContactRow = ContentValues().apply { // Adds the account type and name to the row put(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.type) put(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.name) } // Adds the row to the array contactData.add(rawContactRow) /* * Sets up the phone number data row */ // Sets up the row as a ContentValues object val phoneRow = ContentValues().apply { // Specifies the MIME type for this data row (all data rows must be marked by their type) put(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Adds the phone number and its type to the row put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) } // Adds the row to the array contactData.add(phoneRow) /* * Sets up the email data row */ // Sets up the row as a ContentValues object val emailRow = ContentValues().apply { // Specifies the MIME type for this data row (all data rows must be marked by their type) put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Adds the email address and its type to the row put(ContactsContract.CommonDataKinds.Email.ADDRESS, email) } // Adds the row to the array contactData.add(emailRow) // Creates a new intent for sending to the device's contacts application val insertIntent = Intent(ContactsContract.Intents.Insert.ACTION).apply { // Sets the MIME type to the one expected by the insertion activity type = ContactsContract.RawContacts.CONTENT_TYPE // Sets the new contact name putExtra(ContactsContract.Intents.Insert.NAME, name) // Sets the new company and job title putExtra(ContactsContract.Intents.Insert.COMPANY, company) putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle) /* * Adds the array to the intent's extras. It must be a parcelable object in order to * travel between processes. The device's contacts app expects its key to be * Intents.Insert.DATA */ putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData) } // Send out the intent to start the device's contacts app in its add contact activity. startActivity(insertIntent)
Java
// Gets values from the UI String name = contactNameEditText.getText().toString(); String phone = contactPhoneEditText.getText().toString(); String email = contactEmailEditText.getText().toString(); String company = companyName.getText().toString(); String jobtitle = jobTitle.getText().toString(); // Creates a new intent for sending to the device's contacts application Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION); // Sets the MIME type to the one expected by the insertion activity insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE); // Sets the new contact name insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name); // Sets the new company and job title insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company); insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle); /* * Demonstrates adding data rows as an array list associated with the DATA key */ // Defines an array list to contain the ContentValues objects for each row ArrayList<ContentValues> contactData = new ArrayList<ContentValues>(); /* * Defines the raw contact row */ // Sets up the row as a ContentValues object ContentValues rawContactRow = new ContentValues(); // Adds the account type and name to the row rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.getType()); rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.getName()); // Adds the row to the array contactData.add(rawContactRow); /* * Sets up the phone number data row */ // Sets up the row as a ContentValues object ContentValues phoneRow = new ContentValues(); // Specifies the MIME type for this data row (all data rows must be marked by their type) phoneRow.put( ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE ); // Adds the phone number and its type to the row phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone); // Adds the row to the array contactData.add(phoneRow); /* * Sets up the email data row */ // Sets up the row as a ContentValues object ContentValues emailRow = new ContentValues(); // Specifies the MIME type for this data row (all data rows must be marked by their type) emailRow.put( ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE ); // Adds the email address and its type to the row emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email); // Adds the row to the array contactData.add(emailRow); /* * Adds the array to the intent's extras. It must be a parcelable object in order to * travel between processes. The device's contacts app expects its key to be * Intents.Insert.DATA */ insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData); // Send out the intent to start the device's contacts app in its add contact activity. startActivity(insertIntent);
תקינות הנתונים
מאגר אנשי הקשר מכיל נתונים חשובים ורגישים שהמשתמשים מצפים שיהיו נכונים ועדכניים, ולכן יש לניהול אנשי הקשר כללים מוגדרים היטב לתקינות הנתונים. אתם אחראים לפעול בהתאם לכללים האלה כשאתם משנים נתונים של אנשי קשר. הכללים החשובים מפורטים כאן:
-
תמיד צריך להוסיף שורת
ContactsContract.CommonDataKinds.StructuredNameלכל שורתContactsContract.RawContactsשמוסיפים. -
שורה ב-
ContactsContract.RawContactsבלי שורה ב-ContactsContract.CommonDataKinds.StructuredNameבטבלהContactsContract.Dataעלולה לגרום לבעיות במהלך הצבירה. -
תמיד צריך לקשר שורות
ContactsContract.Dataחדשות לשורת ההורהContactsContract.RawContactsשלהן. -
שורה ב-
ContactsContract.Dataשלא מקושרת ל-ContactsContract.RawContactsלא תופיע באפליקציה לניהול אנשי הקשר במכשיר, ועלולה לגרום לבעיות במתאמי הסנכרון. - לשנות נתונים רק של הנתונים הגולמיים של אנשי הקשר שבבעלותכם.
- חשוב לזכור שניהול אנשי הקשר בדרך כלל מנהל נתונים מכמה סוגים שונים של חשבונות או שירותים אונליין. אתם צריכים לוודא שהאפליקציה משנה או מוחקת רק נתונים בשורות ששייכות לכם, ושהיא מוסיפה רק נתונים עם סוג חשבון ושם חשבון שבשליטתכם.
-
תמיד צריך להשתמש בקבועים שמוגדרים ב-
ContactsContractובמחלקות המשנה שלו לרשויות, למזהי URI של תוכן, לנתיבי URI, לשמות עמודות, לסוגי MIME ולערכיTYPE. - השימוש בקבועים האלה עוזר למנוע שגיאות. בנוסף, תקבלו אזהרות מהקומפיילר אם אחד מהקבועים הוצא משימוש.
שורות של נתונים בהתאמה אישית
אם תיצרו סוגי MIME משלכם ותשתמשו בהם, תוכלו להוסיף, לערוך, למחוק ולאחזר שורות נתונים משלכם בטבלה ContactsContract.Data. השורות מוגבלות לשימוש בעמודה שמוגדרת ב-ContactsContract.DataColumns, אבל אתם יכולים למפות את שמות העמודות הספציפיים לסוג שלכם לשמות העמודות שמוגדרים כברירת מחדל. באפליקציה לניהול אנשי הקשר במכשיר, הנתונים של השורות מוצגים אבל אי אפשר לערוך או למחוק אותם, והמשתמשים לא יכולים להוסיף נתונים. כדי לאפשר למשתמשים לשנות את שורות הנתונים בהתאמה אישית, צריך לספק פעילות עריכה באפליקציה.
כדי להציג את הנתונים בהתאמה אישית, צריך לספק קובץ contacts.xml שמכיל רכיב <ContactsAccountType> ואחד או יותר מרכיבי הצאצא שלו מסוג <ContactsDataKind>. הנושא הזה מוסבר בפירוט בקטע <ContactsDataKind> element.
מידע נוסף על סוגי MIME בהתאמה אישית זמין במדריך יצירת ספק לניהול גישה.
מתאמי סנכרון של ניהול אנשי הקשר
הספק של אנשי הקשר תוכנן במיוחד כדי לטפל בסנכרון של נתוני אנשי הקשר בין מכשיר לבין שירות אונליין. כך המשתמשים יכולים להוריד נתונים קיימים למכשיר חדש ולהעלות נתונים קיימים לחשבון חדש. הסנכרון גם מבטיח שלמשתמשים יהיו הנתונים העדכניים ביותר, בלי קשר למקור של התוספות והשינויים. יתרון נוסף של הסנכרון הוא שנתוני אנשי הקשר זמינים גם כשהמכשיר לא מחובר לרשת.
אפשר להטמיע סנכרון במגוון דרכים, אבל מערכת Android מספקת מסגרת סנכרון של פלאגין שמבצעת באופן אוטומטי את המשימות הבאות:
- המערכת בודקת את זמינות הרשת.
- תזמון וביצוע של סנכרון, על סמך העדפות המשתמש.
- הפעלה מחדש של סנכרונים שהופסקו.
כדי להשתמש במסגרת הזו, צריך לספק פלאגין של מתאם סנכרון. כל מתאם סנכרון הוא ייחודי לשירות ולספק לניהול גישה, אבל יכול לטפל בכמה שמות של חשבונות לאותו שירות. המסגרת גם מאפשרת כמה מתאמי סנכרון לאותו שירות וספק.
קבצים ומחלקות של מתאם סנכרון
מטמיעים מתאם סנכרון כמחלקת משנה של AbstractThreadedSyncAdapter ומתקינים אותו כחלק מאפליקציה ל-Android. המערכת לומדת על מתאם הסנכרון מרכיבים במניפסט של האפליקציה, ומקובץ XML מיוחד שהמניפסט מפנה אליו. קובץ ה-XML מגדיר את סוג החשבון של השירות אונליין ואת הרשות של הספק לניהול גישה, שיחד מזהים באופן ייחודי את המתאם. מתאם הסנכרון לא הופך לפעיל עד שהמשתמש מוסיף חשבון לסוג החשבון של מתאם הסנכרון ומפעיל את הסנכרון לספק לניהול גישה שאיתו מתאם הסנכרון מסתנכרן. בשלב הזה, המערכת מתחילה לנהל את המתאם, וקוראת לו לפי הצורך כדי לסנכרן בין הספק לניהול גישה לבין השרת.
הערה: שימוש בסוג חשבון כחלק מהזיהוי של מתאם הסנכרון מאפשר למערכת לזהות ולקבץ יחד מתאמי סנכרון שניגשים לשירותים שונים מאותו ארגון. לדוגמה, לכל מתאמי הסנכרון של השירותים אונליין של Google יש את אותו סוג חשבון, com.google. כשמשתמשים מוסיפים חשבון Google למכשירים שלהם, כל מתאמי הסנכרון המותקנים לשירותי Google מופיעים יחד. כל מתאם סנכרון שמופיע מסתנכרן עם ספק אחר לניהול גישה במכשיר.
ברוב השירותים המשתמשים נדרשים לאמת את הזהות שלהם לפני שהם מקבלים גישה לנתונים, ולכן מערכת Android מציעה מסגרת אימות שדומה למסגרת של מתאם הסנכרון, ולעיתים קרובות משתמשים בהן ביחד. מסגרת האימות משתמשת במאמתים של יישומי פלאגין שהם מחלקות משנה של AbstractAccountAuthenticator. המאמת מאמת את זהות המשתמש בשלבים הבאים:
- אוסף את השם, הסיסמה או מידע דומה של המשתמש (פרטי הכניסה של המשתמש).
- שליחת פרטי הכניסה לשירות
- בודק את התשובה של השירות.
אם השירות מקבל את פרטי הכניסה, המאמת יכול לשמור אותם לשימוש מאוחר יותר. בגלל מסגרת מאמת החשבונות של הפלאגין, AccountManager יכול לספק גישה לכל אסימון אימות שהמאמת תומך בו ובוחר לחשוף, כמו אסימוני אימות של OAuth2.
למרות שאימות לא נדרש, רוב שירותי אנשי הקשר משתמשים בו. עם זאת, אתם לא חייבים להשתמש במסגרת האימות של Android כדי לבצע אימות.
הטמעה של מתאם סנכרון
כדי להטמיע מתאם סנכרון לניהול אנשי הקשר, קודם צריך ליצור אפליקציה ל-Android שמכילה את הרכיבים הבאים:
-
רכיב
Serviceשמגיב לבקשות מהמערכת לקשר למתאם הסנכרון. -
כשהמערכת רוצה להפעיל סנכרון, היא קוראת ל-method
onBind()של השירות כדי לקבלIBinderלמתאם הסנכרון. כך המערכת יכולה לבצע קריאות בין תהליכים לשיטות של המתאם. -
מתאם הסנכרון בפועל, שמוטמע כמחלקת משנה קונקרטית של
AbstractThreadedSyncAdapter. -
המחלקה הזו מבצעת את העבודה של הורדת נתונים מהשרת, העלאת נתונים מהמכשיר ופתרון התנגשויות. הפעולה העיקרית של המתאם מתבצעת ב-method
onPerformSync(). צריך ליצור מופע של המחלקה הזו כ-singleton. -
מחלקה משנית של
Application. -
המחלקה הזו משמשת כמפעל ל-singleton של מתאם הסנכרון. משתמשים ב-method
onCreate()כדי ליצור מופע של מתאם הסנכרון, ומספקים method סטטי של getter כדי להחזיר את הסינגלטון ל-methodonBind()של השירות של מתאם הסנכרון. -
אופציונלי: רכיב
Serviceשמגיב לבקשות מהמערכת לאימות משתמשים. -
AccountManagerמפעיל את השירות הזה כדי להתחיל את תהליך האימות. ה-methodonCreate()של השירות יוצרת מופע של אובייקט מאמת. כשהמערכת רוצה לאמת חשבון משתמש בשביל מתאם הסנכרון של האפליקציה, היא קוראת ל-methodonBind()של השירות כדי לקבלIBinderלמאמת. כך המערכת יכולה לבצע קריאות בין תהליכים לשיטות של המאמת. -
אופציונלי: מחלקת משנה קונקרטית של
AbstractAccountAuthenticatorשמטפלת בבקשות לאימות. -
המחלקה הזו מספקת שיטות שמופעלות על ידי
AccountManagerכדי לאמת את פרטי הכניסה של המשתמש מול השרת. הפרטים של תהליך האימות משתנים מאוד בהתאם לטכנולוגיית השרת שבה משתמשים. כדי לקבל מידע נוסף על אימות, כדאי לעיין במסמכי התיעוד של תוכנת השרת. - קובצי XML שמגדירים את מתאם הסנכרון והמאמת למערכת.
-
רכיבי השירות של מתאם הסנכרון והמאמת שתוארו קודם מוגדרים ברכיבי
<service>במניפסט של האפליקציה. הרכיבים האלה מכילים<meta-data>רכיבי משנה שמספקים נתונים ספציפיים למערכת:-
הרכיב
<meta-data>של שירות מתאם הסנכרון מפנה אל קובץ ה-XMLres/xml/syncadapter.xml. הקובץ הזה מציין את ה-URI של שירות האינטרנט שיסונכרן עם ספק אנשי הקשר, ואת סוג החשבון של שירות האינטרנט. -
אופציונלי: הרכיב
<meta-data>של המאמת מפנה לקובץ ה-XMLres/xml/authenticator.xml. הקובץ הזה מציין את סוג החשבון שהמאמת תומך בו, וגם את משאבי ממשק המשתמש שמופיעים במהלך תהליך האימות. סוג החשבון שצוין ברכיב הזה חייב להיות זהה לסוג החשבון שצוין למתאם הסנכרון.
-
הרכיב
נתונים של מקורות נתונים ברשתות חברתיות
הטבלאות android.provider.ContactsContract.StreamItems ו-android.provider.ContactsContract.StreamItemPhotos מנהלות את הנתונים שנכנסים מרשתות חברתיות. אתם יכולים לכתוב מתאם סנכרון שמוסיף נתוני סטרימינג מהרשת שלכם לטבלאות האלה, או לקרוא נתוני סטרימינג מהטבלאות האלה ולהציג אותם באפליקציה שלכם, או גם וגם. התכונות האלה מאפשרות לשלב את האפליקציות והשירותים של הרשתות החברתיות שלכם בחוויית הרשתות החברתיות של Android.
טקסט בפיד ברשתות החברתיות
פריטים בסטרימינג תמיד משויכים לנתונים גולמיים של איש קשר. הערך
android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID מקשר לערך
_ID של הנתונים הגולמיים של איש הקשר. סוג החשבון ושם החשבון של הנתונים הגולמיים של איש הקשר מאוחסנים גם בשורה של פריט הסטרימינג.
שומרים את הנתונים מהשידור בעמודות הבאות:
- android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE
- חובה. סוג החשבון של המשתמש עבור הנתונים הגולמיים של איש הקשר שמשויכים לפריט הזה בסטרימינג. חשוב לזכור להגדיר את הערך הזה כשמוסיפים פריט לסטרימינג.
- android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME
- חובה. שם החשבון של המשתמש בנתונים הגולמיים של איש הקשר שמשויך לפריט הזה בסטרימינג. חשוב לזכור להגדיר את הערך הזה כשמוסיפים פריט לסטרימינג.
- עמודות מזהה
-
חובה. כשמוסיפים פריט בסטרימינג, צריך להוסיף את עמודות המזהים הבאות:
- android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID: הערך android.provider.BaseColumns#_ID של איש הקשר שפריט הסטרימינג הזה משויך אליו.
- android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY: הערך של android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY של איש הקשר שפריט הסטרימינג הזה משויך אליו.
- android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID: הערך android.provider.BaseColumns#_ID של הנתונים הגולמיים של איש הקשר שפריט הסטרימינג הזה משויך אליו.
- android.provider.ContactsContract.StreamItemsColumns#COMMENTS
- אופציונלי. אחסון מידע מסכם שאפשר להציג בתחילת פריט בעדכונים.
- android.provider.ContactsContract.StreamItemsColumns#TEXT
-
הטקסט של הפריט בסטרימינג, התוכן שפורסם על ידי מקור הפריט,
או תיאור של פעולה כלשהי שיצרה את הפריט בסטרימינג. העמודה הזו יכולה להכיל כל עיצוב ותמונות של משאבים מוטמעים שניתן לעבד באמצעות
fromHtml(). הספק עשוי לקצר או להוסיף שלוש נקודות לתוכן ארוך, אבל הוא ינסה להימנע מחיתוך תגים. - android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP
- מחרוזת טקסט שמכילה את השעה שבה הפריט בסטרימינג נוסף או עודכן, בפורמט של אלפיות השנייה מאז ראשית זמן יוניקס (Unix epoch). אפליקציות שמוסיפות או מעדכנות פריטים בסטרימינג אחראיות לתחזוקה של העמודה הזו. היא לא מתוחזקת באופן אוטומטי על ידי ניהול אנשי הקשר.
כדי להציג פרטים מזהים של פריטי הסטרימינג, צריך להשתמש ב-android.provider.ContactsContract.StreamItemsColumns#RES_ICON, ב-android.provider.ContactsContract.StreamItemsColumns#RES_LABEL וב-android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE כדי לקשר למשאבים באפליקציה.
הטבלה android.provider.ContactsContract.StreamItems מכילה גם את העמודות android.provider.ContactsContract.StreamItemsColumns#SYNC1 עד android.provider.ContactsContract.StreamItemsColumns#SYNC4 לשימוש בלעדי של מתאמי סנכרון.
תמונות מפיד של רשת חברתית
הטבלה android.provider.ContactsContract.StreamItemPhotos מאחסנת תמונות שמשויכות לפריט בסטרימינג. העמודה android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID בטבלה מקשרת לערכים בעמודה _ID בטבלה android.provider.ContactsContract.StreamItems. הפניות לתמונות מאוחסנות בטבלה בעמודות הבאות:
- android.provider.ContactsContract.StreamItemPhotos#עמודת PHOTO (BLOB).
- ייצוג בינארי של התמונה, שהגודל שלה שונה על ידי הספק לצורך אחסון והצגה. העמודה הזו זמינה לצורך תאימות לדורות קודמים של ספק אנשי הקשר שהשתמשו בה לאחסון תמונות. עם זאת, בגרסה הנוכחית לא מומלץ להשתמש בעמודה הזו כדי לאחסן תמונות. במקום זאת, צריך להשתמש ב-android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID או ב-android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI (שניהם מתוארים בנקודות הבאות) כדי לאחסן תמונות בקובץ. העמודה הזו מכילה עכשיו תמונה ממוזערת של התמונה, שזמינה לקריאה.
- android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID
-
מזהה מספרי של תמונה של נתונים גולמיים של איש קשר. מוסיפים את הערך הזה לקבוע
DisplayPhoto.CONTENT_URIכדי לקבל URI של תוכן שמצביע על קובץ תמונה יחיד, ואז קוראים ל-openAssetFileDescriptor()כדי לקבל נקודת אחיזה לקובץ התמונה. - android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI
-
URI של תוכן שמפנה ישירות לקובץ התמונה שמיוצג בשורה הזו.
קוראים ל-
openAssetFileDescriptor()עם ה-URI הזה כדי לקבל נקודת אחיזה לקובץ התמונה.
שימוש בטבלאות של פיד הרשתות החברתיות
הטבלאות האלה פועלות כמו הטבלאות הראשיות האחרות בניהול אנשי הקשר, אבל:
- כדי לגשת לטבלאות האלה נדרשות הרשאות גישה נוספות. כדי לקרוא מהם, לאפליקציה צריכה להיות ההרשאה android.Manifest.permission#READ_SOCIAL_STREAM. כדי לשנות אותם, לאפליקציה צריכה להיות ההרשאה android.Manifest.permission#WRITE_SOCIAL_STREAM.
-
בטבלה android.provider.ContactsContract.StreamItems, מספר השורות שמאוחסנות לכל נתונים גולמיים של איש קשר מוגבל. אחרי שמגיעים למגבלה הזו, ניהול אנשי הקשר מפנה מקום לשורות חדשות של פריטי סטרימינג על ידי מחיקה אוטומטית של השורות עם הערך הכי ישן של android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP. כדי לקבל את המגבלה, צריך לשלוח שאילתה ל-URI של התוכן android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI. אפשר להשאיר את כל הארגומנטים מלבד ה-URI של התוכן מוגדרים כ-
null. השאילתה מחזירה סמן שמכיל שורה אחת, עם העמודה היחידה android.provider.ContactsContract.StreamItems#MAX_ITEMS.
המחלקה android.provider.ContactsContract.StreamItems.StreamItemPhotos מגדירה טבלת משנה של android.provider.ContactsContract.StreamItemPhotos שמכילה את שורות התמונות של פריט אחד בפיד.
אינטראקציות בפיד של הרשת החברתית
נתוני הפיד החברתי שמנוהלים על ידי ספק אנשי הקשר, בשילוב עם האפליקציה לניהול אנשי הקשר במכשיר, מאפשרים לקשר בין מערכת הרשת החברתית שלכם לאנשי הקשר הקיימים. התכונות הבאות זמינות:
- אם תסנכרנו את שירות הרשת החברתית שלכם עם ניהול אנשי הקשר באמצעות מתאם סנכרון, תוכלו לאחזר את הפעילות האחרונה של אנשי הקשר של המשתמש ולשמור אותה בטבלאות android.provider.ContactsContract.StreamItems ו-android.provider.ContactsContract.StreamItemPhotos לשימוש מאוחר יותר.
- בנוסף לסנכרון הרגיל, אפשר להפעיל את מתאם הסנכרון כדי לאחזר נתונים נוספים כשהמשתמש בוחר איש קשר לצפייה. כך מתאם הסנכרון יכול לאחזר תמונות ברזולוציה גבוהה ואת הפריטים האחרונים בסטרימינג של איש הקשר.
- אם תרשמו התראה באפליקציה לניהול אנשי הקשר במכשיר ובספק אנשי הקשר, תוכלו לקבל Intent כשמישהו יצפה באיש קשר, ובשלב הזה לעדכן את הסטטוס של איש הקשר מהשירות שלכם. הגישה הזו יכולה להיות מהירה יותר ולצרוך פחות רוחב פס מאשר סנכרון מלא עם מתאם סנכרון.
- המשתמשים יכולים להוסיף איש קשר לשירות הרשת החברתית שלכם בזמן שהם מסתכלים על איש הקשר באפליקציה לניהול אנשי הקשר במכשיר. כדי להפעיל את התכונה הזו, צריך להשתמש בתכונה "הזמנת איש קשר". מפעילים אותה באמצעות שילוב של פעילות שמוסיפה איש קשר קיים לרשת, וקובץ XML שמספק לאפליקציה לניהול אנשי הקשר במכשיר ולספק אנשי הקשר את פרטי האפליקציה.
סנכרון רגיל של פריטים בסטרימינג עם ניהול אנשי הקשר זהה לסנכרונים אחרים. למידע נוסף על סנכרון, עיינו בקטע מתאמי סנכרון של ניהול אנשי הקשר. רישום התראות והזמנת אנשי קשר מוסברים בשני הקטעים הבאים.
מתבצע רישום לטיפול בתצוגות של רשתות חברתיות
כדי לרשום את מתאם הסנכרון לקבלת התראות כשהמשתמש צופה באיש קשר שמנוהל על ידי מתאם הסנכרון:
-
יוצרים קובץ בשם
contacts.xmlבספרייהres/xml/של הפרויקט. אם כבר יש לכם את הקובץ הזה, אתם יכולים לדלג על השלב הזה. -
בקובץ הזה, מוסיפים את הרכיב
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">. אם הרכיב הזה כבר קיים, אתם יכולים לדלג על השלב הזה. -
כדי לרשום שירות שמקבל התראה כשהמשתמש פותח את דף הפרטים של איש קשר באפליקציה לניהול אנשי הקשר במכשיר, מוסיפים את המאפיין
viewContactNotifyService="serviceclass"לרכיב, כאשרserviceclassהוא שם המחלקה המלא של השירות שאמור לקבל את ה-Intent מהאפליקציה לניהול אנשי הקשר במכשיר. בשירות ההתראות, משתמשים במחלקה שמרחיבה אתIntentServiceכדי לאפשר לשירות לקבל כוונות. הנתונים ב-Intent הנכנס מכילים את ה-URI של התוכן של הנתונים הגולמיים של איש הקשר שהמשתמש לחץ עליו. משירות ההתראות, אתם יכולים לקשר למתאם הסנכרון ואז להפעיל אותו כדי לעדכן את הנתונים הגולמיים של איש הקשר.
כדי לרשום פעילות שתופעל כשהמשתמש לוחץ על פריט בסטרימינג או על תמונה או על שניהם:
-
יוצרים קובץ בשם
contacts.xmlבספרייהres/xml/של הפרויקט. אם כבר יש לכם את הקובץ הזה, אתם יכולים לדלג על השלב הזה. -
בקובץ הזה, מוסיפים את הרכיב
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">. אם הרכיב הזה כבר קיים, אתם יכולים לדלג על השלב הזה. -
כדי לרשום את אחת מהפעילויות שלכם לטיפול בלחיצה של המשתמש על פריט בפיד באפליקציה לניהול אנשי הקשר במכשיר, הוסיפו את המאפיין
viewStreamItemActivity="activityclass"לרכיב, כאשרactivityclassהוא שם המחלקה המלא של הפעילות שאמורה לקבל את ה-Intent מהאפליקציה לניהול אנשי הקשר במכשיר. -
כדי לרשום את אחת מהפעילויות שלכם לטיפול בלחיצה של המשתמש על תמונת סטרימינג באפליקציה לניהול אנשי הקשר במכשיר, הוסיפו את המאפיין
viewStreamItemPhotoActivity="activityclass"לרכיב, כאשרactivityclassהוא שם המחלקה המלא של הפעילות שאמורה לקבל את ה-Intent מהאפליקציה לניהול אנשי הקשר במכשיר.
הרכיב <ContactsAccountType> מתואר בפירוט בקטע הרכיב<ContactsAccountType>.
ה-Intent הנכנס מכיל את ה-URI של התוכן של הפריט או התמונה שהמשתמש לחץ עליהם. כדי להגדיר פעילויות נפרדות לפריטי טקסט ולתמונות, צריך להשתמש בשני המאפיינים באותו קובץ.
אינטראקציה עם שירות הרשת החברתית שלכם
המשתמשים לא צריכים לצאת מהאפליקציה לניהול אנשי הקשר במכשיר כדי להזמין איש קשר לאתר הרשת החברתית שלכם. במקום זאת, אתם יכולים להגדיר שאפליקציית אנשי הקשר של המכשיר תשלח Intent להזמנת איש הקשר לאחת מהפעילויות שלכם. כדי להגדיר את זה:
-
יוצרים קובץ בשם
contacts.xmlבספרייהres/xml/של הפרויקט. אם כבר יש לכם את הקובץ הזה, אתם יכולים לדלג על השלב הזה. -
בקובץ הזה, מוסיפים את הרכיב
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">. אם הרכיב הזה כבר קיים, אתם יכולים לדלג על השלב הזה. -
מוסיפים את המאפיינים הבאים:
inviteContactActivity="activityclass"-
inviteContactActionLabel="@string/invite_action_label"
activityclassהוא שם המחלקה המלא של הפעילות שאמורה לקבל את ה-Intent. הערךinvite_action_labelהוא מחרוזת טקסט שמוצגת בתפריט הוספת חיבור באפליקציה לניהול אנשי הקשר במכשיר.
הערה: ContactsSource הוא שם תג שהוצא משימוש ב-ContactsAccountType.
הפניה לקובץ contacts.xml
הקובץ contacts.xml מכיל רכיבי XML ששולטים באינטראקציה של מתאם הסנכרון והאפליקציה עם האפליקציה לניהול אנשי הקשר ועם ניהול אנשי הקשר. הרכיבים האלה מתוארים בקטעים הבאים.
הרכיב <ContactsAccountType>
הרכיב <ContactsAccountType> שולט באינטראקציה של האפליקציה עם האפליקציה לניהול אנשי הקשר. התחביר שלו הוא:
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android" inviteContactActivity="activity_name" inviteContactActionLabel="invite_command_text" viewContactNotifyService="view_notify_service" viewGroupActivity="group_view_activity" viewGroupActionLabel="group_action_text" viewStreamItemActivity="viewstream_activity_name" viewStreamItemPhotoActivity="viewphotostream_activity_name">
contained in:
res/xml/contacts.xml
יכול להכיל:
<ContactsDataKind>
תיאור:
מצהירה על רכיבי Android ותוויות ממשק משתמש שמאפשרים למשתמשים להזמין את אחד מאנשי הקשר שלהם לרשת חברתית, להודיע למשתמשים כשאחד מהפידים שלהם ברשת החברתית מתעדכן וכו'.
שימו לב שהקידומת android: לא נדרשת למאפיינים של <ContactsAccountType>.
מאפיינים:
inviteContactActivity- שם המחלקה המלא של הפעילות באפליקציה שרוצים להפעיל כשהמשתמש בוחר באפשרות הוספת חיבור באפליקציה לניהול אנשי הקשר במכשיר.
inviteContactActionLabel-
מחרוזת טקסט שמוצגת לפעילות שצוינה ב-
inviteContactActivity, בתפריט הוספת חיבור. לדוגמה, אפשר להשתמש במחרוזת "מעקב ברשת שלי". אפשר להשתמש במזהה משאב מחרוזות בשביל התווית הזו. viewContactNotifyService- שם המחלקה המלא של שירות באפליקציה שאמור לקבל התראות כשהמשתמש צופה באיש קשר. ההתראה הזו נשלחת על ידי האפליקציה לניהול אנשי הקשר במכשיר. היא מאפשרת לאפליקציה לדחות פעולות שדורשות הרבה נתונים עד שהן נחוצות. לדוגמה, האפליקציה יכולה להגיב להתראה הזו על ידי קריאה והצגה של התמונה ברזולוציה גבוהה של איש הקשר והפריטים האחרונים בפיד החברתי. התכונה הזו מתוארת בפירוט בקטע אינטראקציות בפיד החברתי.
viewGroupActivity- שם המחלקה המלא של פעילות באפליקציה שיכולה להציג מידע על קבוצה. כשמשתמש לוחץ על תווית הקבוצה באפליקציה לניהול אנשי הקשר במכשיר, מוצג ממשק המשתמש של הפעילות הזו.
viewGroupActionLabel-
התווית שמוצגת באפליקציה לניהול אנשי הקשר עבור רכיב אינטראקטיבי שמאפשר
למשתמשים לראות קבוצות באפליקציה.
אפשר להשתמש במזהה משאב של מחרוזת במאפיין הזה.
viewStreamItemActivity- שם המחלקה המלא של Activity באפליקציה, שאפליקציה לניהול אנשי הקשר של המכשיר מפעילה כשהמשתמש לוחץ על פריט בסטרימינג של נתונים גולמיים של איש קשר.
viewStreamItemPhotoActivity- שם המחלקה המלא של Activity באפליקציה, שאפליקציה לניהול אנשי הקשר של המכשיר מפעילה כשהמשתמש לוחץ על תמונה בפריט הסטרימינג של נתונים גולמיים של איש קשר.
הרכיב <ContactsDataKind>
הרכיב <ContactsDataKind> שולט בתצוגה של שורות הנתונים בהתאמה אישית של האפליקציה בממשק המשתמש של האפליקציה לניהול אנשי הקשר. התחביר שלו הוא:
<ContactsDataKind android:mimeType="MIMEtype" android:icon="icon_resources" android:summaryColumn="column_name" android:detailColumn="column_name">
contained in:
<ContactsAccountType>
תיאור:
משתמשים ברכיב הזה כדי שהאפליקציה לניהול אנשי הקשר תציג את התוכן של שורת נתונים בהתאמה אישית כחלק מהפרטים של נתונים גולמיים של איש קשר. כל רכיב צאצא <ContactsDataKind> של <ContactsAccountType> מייצג סוג של שורת נתונים בהתאמה אישית שמתאם הסנכרון מוסיף לטבלה ContactsContract.Data. מוסיפים רכיב <ContactsDataKind> אחד לכל סוג MIME מותאם אישית שבו משתמשים. לא צריך להוסיף את הרכיב אם יש שורת נתונים בהתאמה אישית שלא רוצים להציג בה נתונים.
מאפיינים:
android:mimeType-
סוג ה-MIME המותאם אישית שהגדרתם לאחד מסוגי שורות הנתונים המותאמים אישית בטבלה
ContactsContract.Data. לדוגמה, הערךvnd.android.cursor.item/vnd.example.locationstatusיכול להיות סוג MIME בהתאמה אישית לשורת נתונים שמתעדת את המיקום האחרון הידוע של איש קשר. android:icon- פריט גרפי שניתן להזזה ב-Android, שאפליקציית אנשי הקשר מציגה לצד הנתונים שלכם. כך המשתמשים ידעו שהנתונים מגיעים מהשירות שלכם.
android:summaryColumn- שם העמודה של הערך הראשון מבין שני הערכים שאוחזרו משורת הנתונים. הערך מוצג בשורה הראשונה של הרשומה בשורת הנתונים הזו. השורה הראשונה מיועדת לשמש כסיכום של הנתונים, אבל זה אופציונלי. אפשר לעיין גם במאמר android:detailColumn.
android:detailColumn-
שם העמודה של הערך השני מבין שני הערכים שאוחזרו משורת הנתונים. הערך מוצג בשורה השנייה של הרשומה בשורת הנתונים הזו. מידע נוסף מופיע בתיאור של המדיניות
android:summaryColumn.
תכונות נוספות של ניהול אנשי הקשר
בנוסף לתכונות העיקריות שמתוארות בקטעים הקודמים, ניהול אנשי הקשר מציע את התכונות השימושיות הבאות לעבודה עם נתוני אנשי הקשר:
- קבוצות של אנשי קשר
- תכונות שקשורות לתמונות
קבוצות של אנשי קשר
ניהול אנשי הקשר יכול גם לתייג אוספים של אנשי קשר קשורים באמצעות נתוני קבוצה. אם השרת שמשויך לחשבון משתמש רוצה לנהל קבוצות, מתאם הסנכרון של סוג החשבון צריך להעביר את נתוני הקבוצות בין ניהול אנשי הקשר לבין השרת. כשמשתמשים מוסיפים איש קשר חדש לשרת ואז מוסיפים את איש הקשר הזה לקבוצה חדשה, מתאם הסנכרון צריך להוסיף את הקבוצה החדשה לטבלה ContactsContract.Groups. הקבוצה או הקבוצות שאליהן משתייכים הנתונים הגולמיים של איש הקשר מאוחסנות בטבלה ContactsContract.Data, באמצעות סוג ה-MIME ContactsContract.CommonDataKinds.GroupMembership.
אם אתם מתכננים מתאם סנכרון שיוסיף נתונים גולמיים של אנשי קשר מהשרת לניהול אנשי הקשר, ואתם לא משתמשים בקבוצות, אתם צריכים להגדיר לניהול אנשי הקשר להציג את הנתונים שלכם. בקוד שמופעל כשמשתמש מוסיף חשבון למכשיר, מעדכנים את השורה ContactsContract.Settings שניהול אנשי הקשר מוסיף לחשבון. בשורה הזו, מגדירים את הערך של העמודה Settings.UNGROUPED_VISIBLE ל-1. כשעושים את זה, ספק אנשי הקשר תמיד יציג את נתוני אנשי הקשר, גם אם לא משתמשים בקבוצות.
התמונות של איש הקשר
הטבלה ContactsContract.Data מאחסנת תמונות כשורות עם סוג MIME Photo.CONTENT_ITEM_TYPE. העמודה CONTACT_ID של השורה מקושרת לעמודה _ID של הנתונים הגולמיים של איש הקשר שאליו היא שייכת.
הכיתה ContactsContract.Contacts.Photo מגדירה טבלת משנה של ContactsContract.Contacts שמכילה מידע על התמונה הראשית של איש הקשר, שהיא התמונה הראשית של הנתונים הגולמיים הראשיים של איש הקשר. באופן דומה,
הכיתה ContactsContract.RawContacts.DisplayPhoto מגדירה טבלת משנה
של ContactsContract.RawContacts שמכילה מידע על התמונה הראשית
של נתונים גולמיים של איש קשר.
במאמרי העזרה של ContactsContract.Contacts.Photo ו-ContactsContract.RawContacts.DisplayPhoto יש דוגמאות לאחזור מידע על תמונות. אין מחלקת נוחות לאחזור התמונה הממוזערת הראשית של נתונים גולמיים של איש קשר, אבל אפשר לשלוח שאילתה לטבלה ContactsContract.Data, ולבחור בעמודות _ID, Photo.CONTENT_ITEM_TYPE ו-IS_PRIMARY של הנתונים הגולמיים של איש הקשר כדי למצוא את שורת התמונה הראשית של הנתונים הגולמיים של איש הקשר.
נתוני הפיד החברתי של אדם מסוים עשויים לכלול גם תמונות. התמונות האלה מאוחסנות בטבלה android.provider.ContactsContract.StreamItemPhotos, שמתוארת בפירוט רב יותר בקטע תמונות בפיד של הרשת החברתית.