ספק אנשי הקשר הוא רכיב חזק וגמיש של Android שמנהל את המאגר המרכזי של המכשיר לנתונים על אנשים. ספק אנשי הקשר הוא מקור הנתונים שמופיעים באפליקציית אנשי הקשר של המכשיר. אפשר גם לגשת לנתונים שלו באפליקציה שלכם ולהעביר נתונים בין המכשיר לשירותים אונליין. הספק מארח מגוון רחב של מקורות נתונים ומנסה לנהל כמה שיותר נתונים לגבי כל אדם, וכתוצאה מכך הארגון שלו מורכב. לכן, ה-API של הספק כולל קבוצה נרחבת של ממשקים וסיווגים של חוזים שמאפשרים גם אחזור וגם שינוי של נתונים.
במדריך הזה נסביר את הנושאים הבאים:
- המבנה הבסיסי של הספק.
- איך מאחזרים נתונים מהספק.
- איך לשנות נתונים אצל הספק.
- איך לכתוב מתאם לסנכרון לצורך סנכרון נתונים מהשרת שלכם לספק אנשי הקשר.
במדריך הזה אנחנו יוצאים מנקודת הנחה שאתם מכירים את העקרונות הבסיסיים של ספקי תוכן ל-Android. למידע נוסף על ספקי תוכן ב-Android, אפשר לעיין במדריך מושגי היסוד בנושא ספקי תוכן.
הארגון של ניהול אנשי הקשר
ניהול אנשי הקשר הוא רכיב של ספק תוכן ב-Android. הוא שומר שלושה סוגים של נתונים על אדם, שכל אחד מהם תואם לטבלה שהספק מציע, כפי שמתואר באיור 1:
בדרך כלל מתייחסים לשלושת הטבלאות לפי שמות הכיתות שלהן בחוזה. הכיתות מגדירות קבועים למזהי URI של תוכן, לשמות עמודות ולערכים של עמודות שבהם משתמשות הטבלאות:
-
טבלה של
ContactsContract.Contacts
- שורות שמייצגות אנשים שונים, על סמך צבירת שורות קשר גולמיות.
-
טבלה של
ContactsContract.RawContacts
- שורות שמכילות סיכום של הנתונים של אדם, ספציפיים לחשבון ולסוג של המשתמש.
-
טבלה של
ContactsContract.Data
- שורות שמכילות את הפרטים של איש הקשר הגולמי, כמו כתובות אימייל או מספרי טלפון.
הטבלאות האחרות שמיוצגות על ידי כיתות חוזה ב-ContactsContract
הן טבלאות עזר שספק אנשי הקשר משתמש בהן כדי לנהל את הפעולות שלו או לתמוך
בפונקציות ספציפיות באנשי הקשר או באפליקציות הטלפוניה של המכשיר.
אנשי קשר גולמיים
איש קשר בסיסי מייצג את הנתונים של אדם שמגיעים מסוג חשבון אחד ומשם חשבון אחד. מכיוון שספק אנשי הקשר מאפשר יותר משירות אינטרנט אחד כמקור לנתונים של אדם, ספק אנשי הקשר מאפשר כמה אנשי קשר גולמיים של אותו אדם. כמה אנשי קשר גולמיים מאפשרים למשתמש גם לשלב את הנתונים של אדם מסוים מכמה חשבונות מאותו סוג.
רוב הנתונים של איש קשר בפורמט גולמי לא מאוחסנים בטבלה ContactsContract.RawContacts
. במקום זאת, הוא מאוחסן בשורה אחת או יותר בטבלה ContactsContract.Data
. לכל שורת נתונים יש עמודה Data.RAW_CONTACT_ID
שמכילה את הערך RawContacts._ID
של שורת ההורה ContactsContract.RawContacts
.
עמודות חשובות של אנשי קשר בפורמט גולמי
העמודות החשובות בטבלה ContactsContract.RawContacts
מפורטות בטבלה 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', שיש לה שלושה חשבונות משתמשים מוגדרים במכשיר:
emily.dickinson@gmail.com
emilyd@gmail.com
- חשבון Twitter "belle_of_amherst"
המשתמש הפעיל את האפשרות סנכרון אנשי קשר בכל שלושת החשבונות האלה בהגדרות חשבונות.
נניח ש-Emily Dickinson פותחת חלון דפדפן, נכנסת ל-Gmail בתור emily.dickinson@gmail.com
, פותחת את אנשי הקשר ומוסיפה את Thomas Higginson. בהמשך, היא מתחברת ל-Gmail בתור emilyd@gmail.com
ושולחת אימייל אל 'Thomas Higginson', וכך הוא מתווסף באופן אוטומטי כאיש קשר. היא גם עוקבת אחרי 'colonel_tom' (מזהה Twitter של Thomas Higginson) ב-Twitter.
כתוצאה מהפעולה הזו, ניהול אנשי הקשר יוצר שלושה אנשי קשר גולמיים:
-
איש קשר גולמי של 'Thomas Higginson' שמשויך ל-
emily.dickinson@gmail.com
. סוג חשבון המשתמש הוא Google. -
איש קשר גולמי שני של 'Thomas Higginson' שמשויך ל-
emilyd@gmail.com
. סוג חשבון המשתמש הוא גם Google. יש איש קשר גולמי שני, למרות שהשם זהה לשם קודם, כי האדם נוסף לחשבון משתמש אחר. - איש קשר גולמי שלישי בשם 'Thomas Higginson' שמשויך לחשבון 'belle_of_amherst'. סוג חשבון המשתמש הוא Twitter.
נתונים
כפי שצוין קודם, הנתונים של איש קשר גולמי מאוחסנים בשורה ContactsContract.Data
שמקושרת לערך _ID
של איש הקשר הגולמי. כך אפשר ליצור כמה מופעים של אותו סוג נתונים, כמו כתובות אימייל או מספרי טלפון, לאותו איש קשר גולמי. לדוגמה, אם ל-'Thomas Higginson' ב-emilyd@gmail.com
(שורת איש הקשר הגולמי של Thomas Higginson שמשויכת לחשבון 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
שזמינות לכולם, ועוד ארבע עמודות כלליות בשמות 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 מפורטות הכיתות הנפוצות ביותר של שמות עמודות ספציפיות לסוג:
מחלקת מיפוי | סוג הנתונים | הערות |
---|---|---|
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 מוצגת היחסות בין שלוש הטבלאות הראשיות.
זהירות: אם אתם מפרסמים את האפליקציה שלכם בחנות 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
(משפיע רק על סוגי הנתונים Email, Phone ו-Callable)
אם האפליקציות שלכם ניגשות לשדות או לממשקי ה-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 מוצגת ההתאמה של ספק אנשי הקשר לזרימת הנתונים על אנשים. בתיבה 'מתאמי סנכרון', כל מתאם מסומן לפי סוג החשבון שלו.
הרשאות נדרשות
אפליקציות שרוצות לגשת לספק אנשי הקשר צריכות לבקש את ההרשאות הבאות:
- הרשאת קריאה לטבלה אחת או יותר
-
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 אם איש הקשר הוא פרופיל המשתמש.
מטא-נתונים של ניהול אנשי הקשר
שירות ניהול אנשי הקשר מנהל נתונים שמתעדים את המצב של נתוני אנשי הקשר במאגר. המטא-נתונים האלה לגבי המאגר מאוחסנים במקומות שונים, כולל השורות בטבלאות Raw Contacts, Data ו-Contacts, בטבלה ContactsContract.Settings
ובטבלה ContactsContract.SyncState
. בטבלה הבאה מפורטת ההשפעה של כל אחד מהמטא-נתונים האלה:
טבלה | עמודה | ערכים | משמעות |
---|---|---|---|
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
כדי להציג את כל שורות הנתונים מכל אנשי הקשר הגולמיים שמשויכים לאיש הקשר שנבחר.
קטע הקוד הזה נלקח מהפעילות 'פרטים':
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()
. אחד מהארגומנטים הנכנסים לשיטה הזו הוא Cursor
עם תוצאות השאילתה. באפליקציה שלכם, תוכלו לקבל את הנתונים מ-Cursor
כדי להציג אותם או להמשיך לעבוד איתם.
שינוי של מספר פריטים בו-זמנית
כשהדבר אפשרי, מומלץ להוסיף, לעדכן ולמחוק נתונים ב-Contacts Provider ב'מצב באצווה'. לשם כך, יוצרים ArrayList
של אובייקטים מסוג ContentProviderOperation
ומפעילים את applyBatch()
. מכיוון שספק אנשי הקשר מבצע את כל הפעולות ב-applyBatch()
בעסקה אחת, השינויים שלכם לעולם לא יגרמו למצב לא עקבי במאגר אנשי הקשר. שינוי בכמות גדולה מאפשר גם להוסיף בו-זמנית איש קשר בסיסי ואת פרטיו המפורטים.
הערה: כדי לשנות איש קשר גולמי יחיד, מומלץ לשלוח כוונה (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
, ואם מנסים לבצע הפניה לאחור לתוצאה של פעולה שעדיין לא הוחלו, מתקבלת הודעת השגיאהException
ב-withValueBackReference()
.
בקטעי הקוד הבאים מוסבר איך להוסיף אנשי קשר ונתונים גולמיים חדשים באצווה. הם כוללים קוד שמגדיר נקודת כניעה ומשתמש בהפניה לאחור.
קטע הקוד הראשון מאחזר את פרטי הקשר מממשק המשתמש. בשלב הזה, המשתמש כבר בחר את החשבון שאליו צריך להוסיף את איש הקשר הגולמי החדש.
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());
בשלב הבא, הקוד יוצר שורות נתונים לשורות של השם המוצג, הטלפון וכתובת האימייל.
כל אובייקט של ה-builder של הפעולה משתמש ב-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
שמתאים לאכיפה של אילוץ באמצעות השיטהnewAssertQuery(Uri)
. ב-URI של התוכן, משתמשים ב-RawContacts.CONTENT_URI
עם ה-_ID
של איש הקשר הגולמי שמצורף אליו. -
באובייקט
ContentProviderOperation.Builder
, צריך להפעיל את הפונקציהwithValue()
כדי להשוות את העמודהVERSION
למספר הגרסה שאתם מקבלים. -
לאותו
ContentProviderOperation.Builder
, צריך להפעיל אתwithExpectedCount()
כדי לוודא שרק שורה אחת נבדקת על ידי ההצהרה הזו. -
קוראים ל-
build()
כדי ליצור את האובייקטContentProviderOperation
, ואז מוסיפים את האובייקט הזה כאובייקט הראשון ב-ArrayList
ששולחים ל-applyBatch()
. - מחילים את עסקת האצווה.
אם שורת איש הקשר הגולמית מתעדכנת על ידי פעולה אחרת בין הזמן שבו קוראים את השורה לבין הזמן שבו מנסים לשנות אותה, הבדיקה 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 }
אחזור ושינוי באמצעות כוונות
שליחת כוונה לאפליקציית אנשי הקשר של המכשיר מאפשרת לכם לגשת לספק אנשי הקשר באופן עקיף. הכוונה מפעילה את ממשק המשתמש של אפליקציית אנשי הקשר במכשיר, שבו המשתמשים יכולים לבצע פעולות שקשורות לאנשי הקשר. עם סוג הגישה הזה, המשתמשים יכולים:
- בוחרים איש קשר מהרשימה ומחזירים אותו לאפליקציה לצורך המשך עבודה.
- לערוך את הפרטים של איש קשר קיים.
- להוסיף איש קשר חדש ללא עיבוד לכל אחד מהחשבונות שלהם.
- מחיקה של איש קשר או של נתוני אנשי קשר.
אם המשתמש מזין או מעדכן נתונים, אפשר לאסוף את הנתונים קודם ולשלוח אותם כחלק מהכוונה.
כשמשתמשים בכוונות (intents) כדי לגשת לספק אנשי הקשר דרך אפליקציית אנשי הקשר של המכשיר, לא צריך לכתוב ממשק משתמש או קוד משלכם כדי לגשת לספק. בנוסף, לא צריך לבקש הרשאה לקריאה או לכתיבה מהספק. אפליקציית אנשי הקשר של המכשיר יכולה להעניק לכם הרשאת קריאה לאיש קשר, ומכיוון שאתם מבצעים שינויים בספק דרך אפליקציה אחרת, אין צורך בהרשאות כתיבה.
התהליך הכללי לשליחת כוונה לגשת לספק מתואר בפירוט במדריך
בסיסים לספקי תוכן בקטע 'גישה לנתונים באמצעות כוונות'. הפעולה, סוג ה-MIME וערכים של נתונים שבהם משתמשים במשימות הזמינות מפורטים בטבלה 4, ואילו הערכים הנוספים שבהם אפשר להשתמש עם putExtra()
מפורטים במסמכי העזרה של ContactsContract.Intents.Insert
:
משימה | פעולה | נתונים | סוג MIME | הערות |
---|---|---|---|---|
בחירת איש קשר מרשימה | ACTION_PICK |
אחת מהאפשרויות הבאות:
|
צולם בלי מבזק |
הצגת רשימה של אנשי קשר גולמיים או רשימה של נתונים מאיש קשר גולמי, בהתאם לסוג ה-URI של התוכן שסיפקתם.
קוראים לפונקציה |
הוספת איש קשר חדש בפורמט גולמי | Insert.ACTION |
לא רלוונטי |
RawContacts.CONTENT_TYPE , סוג MIME של קבוצת אנשי קשר גולמיים.
|
המסך הוספת איש קשר באפליקציית אנשי הקשר של המכשיר מוצג. מוצגים הערכים הנוספים שמוסיפים לכוונה. אם שולחים את הבקשה עם startActivityForResult() , ה-URI של התוכן של איש הקשר הגולמי שנוסף מחדש מועבר בחזרה לשיטת ה-callback onActivityResult() של הפעילות, בארגומנט Intent , בשדה data. כדי לקבל את הערך, קוראים לפונקציה getData() .
|
עריכת איש קשר | ACTION_EDIT |
CONTENT_LOOKUP_URI לאיש הקשר. הפעילות של עורך הרשאות תאפשר למשתמש לערוך את כל הנתונים שמשויכים לאיש הקשר הזה.
|
Contacts.CONTENT_ITEM_TYPE , איש קשר יחיד. |
הצגת המסך 'עריכת איש קשר' באפליקציית אנשי הקשר. מוצגים הערכים הנוספים שמוסיפים לכוונה. כשהמשתמש לוחץ על סיום כדי לשמור את העריכות, הפעילות חוזרת לחזית. |
הצגת בורר שאפשר גם להוסיף נתונים | ACTION_INSERT_OR_EDIT |
לא רלוונטי |
CONTENT_ITEM_TYPE
|
כוונת החיפוש הזו תמיד מציגה את מסך הבחירה של אפליקציית אנשי הקשר. המשתמש יכול לבחור איש קשר לעריכה או להוסיף איש קשר חדש. מסך העריכה או המסך להוספה יופיעו, בהתאם לבחירה של המשתמש, ונתוני ה-extras שתעבירו בכוונה יוצגו. אם באפליקציה מוצגים פרטים ליצירת קשר כמו כתובת אימייל או מספר טלפון, אפשר להשתמש בכוונה הזו כדי לאפשר למשתמש להוסיף את הפרטים לאיש קשר קיים.
איש קשר,
הערה: אין צורך לשלוח ערך של שם בפרמטרים הנוספים של הכוונה הזו, כי המשתמש תמיד בוחר שם קיים או מוסיף שם חדש. בנוסף, אם תשלחו שם והמשתמש יבחר לערוך אותו, השם שתשלחו יופיע באפליקציית אנשי הקשר ויחליף את הערך הקודם. אם המשתמש לא שם לב לכך ושומר את העריכה, הערך הישן יימחק. |
אפליקציית אנשי הקשר של המכשיר לא מאפשרת למחוק איש קשר בסיסי או את הנתונים שלו באמצעות כוונה. במקום זאת, כדי למחוק איש קשר בפורמט גולמי, משתמשים ב-ContentResolver.delete()
או ב-ContentProviderOperation.newDelete()
.
קטע הקוד הבא מראה איך ליצור ולשלוח כוונה שמוסיפה איש קשר ונתונים גולמיים חדשים:
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
למתאם הסנכרון. כך המערכת יכולה לבצע קריאות בין תהליכים ל-methods של המתאם. -
מתאם הסנכרון בפועל, שמיושם כסוג משנה קונקרטי של
AbstractThreadedSyncAdapter
. -
הכיתה הזו מבצעת את הורדת הנתונים מהשרת, העלאת הנתונים מהמכשיר ופתרון של קונפליקטים. העבודה העיקרית של המתאם מתבצעת ב-method
onPerformSync()
. צריך ליצור מופע של המחלקה הזו כ-singleton. -
מחלקה משנית של
Application
. -
הכיתה הזו משמשת כמפעל ליחידה היחידה של מתאם הסנכרון. משתמשים בשיטה
onCreate()
כדי ליצור מופע של מתאם הסנכרון, ומספקים שיטה סטטית מסוג 'getter' כדי להחזיר את ה-Singleton לשיטהonBind()
של השירות של מתאם הסנכרון. -
אופציונלי: רכיב
Service
שמגיב לבקשות מהמערכת לאימות משתמשים. -
AccountManager
מפעיל את השירות הזה כדי להתחיל את תהליך האימות. שיטתonCreate()
של השירות יוצרת אובייקט של מאמת. כשהמערכת רוצה לאמת חשבון משתמש למתאמת הסנכרון של האפליקציה, היא קורא לשיטהonBind()
של השירות כדי לקבלIBinder
לאימות. כך המערכת יכולה לבצע קריאות חוצות-תהליכים לשיטות של מאמת. -
אופציונלי: Subclass קונקרטי של
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
- מחרוזת טקסט שמכילה את הזמן שבו פריט הסטרימינג הוכנס או עודכן, בפורמט של מיליאקונדות מאז תחילת הזמן. אפליקציות שמוסיפות או מעדכנות פריטים בסטרימינג אחראיות על ניהול העמודה הזו. היא לא מנוהלת באופן אוטומטי על ידי ספק אנשי הקשר.
כדי להציג מידע מזהה על הפריטים בסטרימינג, אפשר להשתמש ב-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
. השאילתה מחזירה Cursor שמכיל שורה אחת עם העמודה היחידה android.provider.ContactsContract.StreamItems#MAX_ITEMS.
הכיתה android.provider.ContactsContract.StreamItems.StreamItemPhotos מגדירה טבלת משנה של android.provider.ContactsContract.StreamItemPhotos שמכילה את שורות התמונות של פריט אחד במקור החדשות.
אינטראקציות עם שידור חי ברשתות חברתיות
נתוני הסטרימינג החברתי שמנוהלים על ידי ספק אנשי הקשר, בשילוב עם אפליקציית אנשי הקשר של המכשיר, מספקים דרך יעילה לחבר את מערכת הרשתות החברתיות לאנשי הקשר הקיימים. התכונות הבאות זמינות:
- כשמסנכרנים את שירות הרשת החברתית עם ספק אנשי הקשר באמצעות מתאם סנכרון, אפשר לאחזר את הפעילות האחרונה של אנשי הקשר של המשתמש ולאחסן אותה בטבלאות android.provider.ContactsContract.StreamItems ו-android.provider.ContactsContract.StreamItemPhotos לשימוש עתידי.
- בנוסף לסנכרון הרגיל, אפשר להפעיל את מתאם הסנכרון כדי לאחזר נתונים נוספים כשהמשתמש בוחר איש קשר להצגה. כך מתאם הסנכרון יוכל לאחזר תמונות ברזולוציה גבוהה ואת הפריטים האחרונים שפורסמו בסטורי של איש הקשר.
- אם תירשמו התראה באפליקציית אנשי הקשר של המכשיר ובספק אנשי הקשר, תוכלו לקבל כוונה כשאיש קשר מוצג, ובשלב הזה לעדכן את הסטטוס של איש הקשר מהשירות שלכם. הגישה הזו עשויה להיות מהירה יותר ולצרוך פחות רוחב פס מאשר סנכרון מלא באמצעות מתאם סנכרון.
- המשתמשים יכולים להוסיף איש קשר לשירות הרשת החברתית שלכם כשהם צופים באיש הקשר באפליקציית אנשי הקשר של המכשיר. כדי להפעיל את התכונה הזו, צריך להשתמש בתכונה 'הזמנת איש קשר', שמפעילים באמצעות שילוב של פעילות שמוסיפה איש קשר קיים לרשת, וקובץ XML שמספק לאפליקציית אנשי הקשר של המכשיר ולספק אנשי הקשר את פרטי האפליקציה.
סנכרון קבוע של פריטי הסטרימינג עם ספק אנשי הקשר זהה לסנכרון עם ספקים אחרים. מידע נוסף על סנכרון זמין בקטע מתאמי סנכרון של ספקי אנשי קשר. בקטעים הבאים מוסבר איך לרשום התראות ולהזמין אנשי קשר.
רישום לטיפול בבקשות לצפיות ברשתות חברתיות
כדי לרשום את מתאם הסנכרון לקבלת התראות כשהמשתמש מציג איש קשר שמנוהל על ידי מתאם הסנכרון:
-
יוצרים קובץ בשם
contacts.xml
בתיקייהres/xml/
של הפרויקט. אם כבר יש לכם את הקובץ הזה, אתם יכולים לדלג על השלב הזה. -
בקובץ הזה, מוסיפים את הרכיב
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. אם הרכיב הזה כבר קיים, אפשר לדלג על השלב הזה. -
כדי לרשום שירות שיקבל התראה כשהמשתמש יפתח את דף הפרטים של איש קשר באפליקציית אנשי הקשר של המכשיר, מוסיפים את המאפיין
viewContactNotifyService="serviceclass"
לאלמנט, כאשרserviceclass
הוא שם הכיתה המלא של השירות שצריך לקבל את הכוונה מאפליקציית אנשי הקשר של המכשיר. בשירות ההתראות, משתמשים בכיתה שמרחיבה אתIntentService
כדי לאפשר לשירות לקבל כוונות. הנתונים בכוונה הנכנסת מכילים את ה-URI של התוכן של פרטי הקשר הגולמיים שהמשתמש לחץ עליהם. משירות ההתראות, אפשר לקשר את מתאם הסנכרון ולאחר מכן להפעיל אותו כדי לעדכן את הנתונים של איש הקשר הגולמי.
כדי לרשום פעילות שתופעל כשהמשתמש לוחץ על פריט בסטרימינג או על תמונה, או על שניהם:
-
יוצרים קובץ בשם
contacts.xml
בתיקייהres/xml/
של הפרויקט. אם כבר יש לכם את הקובץ הזה, אתם יכולים לדלג על השלב הזה. -
בקובץ הזה, מוסיפים את הרכיב
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. אם הרכיב הזה כבר קיים, אפשר לדלג על השלב הזה. -
כדי לרשום אחת מהפעילויות שלכם לטפל במקרה שבו המשתמש לוחץ על פריט בסטרימינג באפליקציית אנשי הקשר של המכשיר, מוסיפים את המאפיין
viewStreamItemActivity="activityclass"
לאלמנט, כאשרactivityclass
הוא שם הכיתה המלא של הפעילות שאמורה לקבל את הכוונה מאפליקציית אנשי הקשר של המכשיר. -
כדי לרשום אחת מהפעילויות שלכם לטפל במקרה שבו המשתמש לוחץ על תמונה בסטרים באפליקציית אנשי הקשר של המכשיר, מוסיפים את המאפיין
viewStreamItemPhotoActivity="activityclass"
לאלמנט, כאשרactivityclass
הוא שם הכיתה המלא של הפעילות שאמורה לקבל את ה-Intent מאפליקציית אנשי הקשר של המכשיר.
רכיב <ContactsAccountType>
מתואר בפירוט רב יותר בקטע הרכיב<ContactsAccountType>.
הכוונה הנכנסת מכילה את URI התוכן של הפריט או התמונה שהמשתמש לחץ עליהם. כדי ליצור פעילויות נפרדות לפריטי טקסט ולתמונות, צריך להשתמש בשני המאפיינים באותו קובץ.
אינטראקציה עם שירות הרשת החברתית
המשתמשים לא צריכים לצאת מאפליקציית אנשי הקשר של המכשיר כדי להזמין איש קשר לאתר של הרשת החברתית. במקום זאת, אפשר להגדיר שאפליקציית אנשי הקשר במכשיר תשלח כוונה להזמנת איש הקשר לאחת מהפעילויות שלכם. כדי להגדיר זאת:
-
יוצרים קובץ בשם
contacts.xml
בתיקייהres/xml/
של הפרויקט. אם כבר יש לכם את הקובץ הזה, אתם יכולים לדלג על השלב הזה. -
בקובץ הזה, מוסיפים את הרכיב
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. אם הרכיב הזה כבר קיים, אפשר לדלג על השלב הזה. -
מוסיפים את המאפיינים הבאים:
inviteContactActivity="activityclass"
-
inviteContactActionLabel="@string/invite_action_label"
activityclass
הוא שם המחלקה המלא של הפעילות שאמורה לקבל את הכוונה. הערך שלinvite_action_label
הוא מחרוזת טקסט שמוצגת בתפריט Add Connection באפליקציית אנשי הקשר של המכשיר.
הערה: 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">
נכלל ב:
res/xml/contacts.xml
יכולים להכיל:
<ContactsDataKind>
תיאור:
הקוד מכריז על רכיבי Android ותוויות של ממשק משתמש שמאפשרים למשתמשים להזמין אחד מאנשי הקשר שלהם לרשת חברתית, להודיע למשתמשים כשאחד מהפידים שלהם ברשת החברתית מתעדכן וכו'.
שימו לב שקידומת המאפיין android:
לא נדרשת למאפיינים של <ContactsAccountType>
.
מאפיינים:
inviteContactActivity
- שם הכיתה המלא של הפעילות באפליקציה שרוצים להפעיל כשהמשתמש בוחר באפשרות Add connection באפליקציית אנשי הקשר של המכשיר.
inviteContactActionLabel
-
מחרוזת טקסט שמוצגת לפעילות שצוינה ב-
inviteContactActivity
, בתפריט Add connection. לדוגמה, אפשר להשתמש במחרוזת 'לעקוב ברשת שלי'. אפשר להשתמש במזהה של משאב מחרוזת בתווית הזו. viewContactNotifyService
- שם הכיתה המלא של שירות באפליקציה שאמור לקבל התראות כשהמשתמש מציג איש קשר. ההתראה הזו נשלחת על ידי אפליקציית אנשי הקשר במכשיר, והיא מאפשרת לאפליקציה לדחות פעולות שמתבצעות באמצעות שימוש רב בנתונים עד שהן נדרשות. לדוגמה, האפליקציה יכולה להגיב להתראה הזו על ידי קריאה והצגה של התמונה באיכות גבוהה של איש הקשר ושל הפריטים האחרונים בסטטוס שלו ברשתות החברתיות. תיאור מפורט יותר של התכונה הזו זמין בקטע אינטראקציות בסטרים של רשתות חברתיות.
viewGroupActivity
- שם הכיתה המלא של פעילות באפליקציה שיכולה להציג מידע על קבוצות. כשהמשתמש לוחץ על תווית הקבוצה באפליקציית אנשי הקשר במכשיר, מוצג ממשק המשתמש של הפעילות הזו.
viewGroupActionLabel
-
התווית שמוצגת באפליקציית אנשי הקשר עבור אמצעי בקרה בממשק המשתמש שמאפשר למשתמש להציג קבוצות באפליקציה.
אפשר להשתמש במזהה משאב של מחרוזת במאפיין הזה.
viewStreamItemActivity
- שם הכיתה המלא של פעילות באפליקציה, שאפליקציית אנשי הקשר במכשיר מפעילה כשהמשתמש לוחץ על פריט בסטרימינג של איש קשר גולמי.
viewStreamItemPhotoActivity
- שם הכיתה המלא של פעילות באפליקציה שלכם, שאפליקציית אנשי הקשר במכשיר מפעילה כשהמשתמש לוחץ על תמונה בפריט בסטרימינג של איש קשר גולמי.
האלמנט <ContactsDataKind>
הרכיב <ContactsDataKind>
קובע את הצגת שורות הנתונים בהתאמה אישית של האפליקציה בממשק המשתמש של אפליקציית אנשי הקשר. התחביר שלו הוא:
<ContactsDataKind android:mimeType="MIMEtype" android:icon="icon_resources" android:summaryColumn="column_name" android:detailColumn="column_name">
נכלל ב:
<ContactsAccountType>
תיאור:
אפשר להשתמש ברכיב הזה כדי להציג באפליקציית אנשי הקשר את התוכן של שורת נתונים בהתאמה אישית כחלק מהפרטים של איש קשר גולמי. כל רכיב צאצא של <ContactsDataKind>
ב-<ContactsAccountType>
מייצג סוג של שורת נתונים בהתאמה אישית שהמתאם לסנכרון מוסיף לטבלה ContactsContract.Data
. מוסיפים רכיב <ContactsDataKind>
אחד לכל סוג MIME מותאם אישית שבו אתם משתמשים. אין צורך להוסיף את הרכיב אם יש לכם שורת נתונים מותאמת אישית שאתם לא רוצים להציג בה נתונים.
מאפיינים:
android:mimeType
-
סוג ה-MIME המותאם אישית שהגדרתם לאחד מסוגי השורות של הנתונים בהתאמה אישית בטבלה
ContactsContract.Data
. לדוגמה, הערךvnd.android.cursor.item/vnd.example.locationstatus
יכול להיות סוג MIME בהתאמה אישית של שורת נתונים שמתעדת את המיקום האחרון הידוע של איש הקשר. android:icon
- משאב drawable ב-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, שמתוארת בפירוט בקטע תמונות מהעדכונים של החברים ברשתות החברתיות.