ספק אנשי הקשר הוא רכיב Android חזק וגמיש שמנהל את מאגר הנתונים המרכזי של המכשיר לגבי אנשים. ספק אנשי הקשר הוא מקור הנתונים שמוצגים באפליקציית אנשי הקשר במכשיר. אפשר גם לגשת לנתונים שלו באפליקציה שלכם ולהעביר נתונים בין המכשיר לשירותים אונליין. הספק תומך במגוון רחב של מקורות נתונים ומנסה לנהל כמה שיותר נתונים עבור כל אדם, ולכן הארגון שלו מורכב. לכן, ה-API של הספק כולל קבוצה נרחבת של מחלקות וממשקים של חוזים שמקלים על אחזור נתונים ועל שינוי שלהם.
במדריך הזה נסביר את הנושאים הבאים:
- המבנה הבסיסי של הספק.
- איך מאחזרים נתונים מהספק.
- איך משנים נתונים אצל הספק.
- איך כותבים מתאם סינכרון לסינכרון נתונים מהשרת לספק אנשי הקשר.
במדריך הזה אנחנו יוצאים מנקודת הנחה שאתם מכירים את העקרונות הבסיסיים של ספקי תוכן ב-Android. מידע נוסף על ספקי תוכן ב-Android זמין במדריך מושגי יסוד בנושא ספקי תוכן.
הארגון של ספק אנשי הקשר
ספק אנשי הקשר הוא רכיב של ספק תוכן ב-Android. הוא שומר שלושה סוגים של נתונים על אדם מסוים, וכל אחד מהם תואם לטבלה שהספק מציע, כמו שמוצג באיור 1:

איור 1. מבנה הטבלה של ספק אנשי הקשר.
שלושת הטבלאות האלה מכונות בדרך כלל בשמות של מחלקות החוזים שלהן. המחלקות מגדירות קבועים עבור כתובות URI של תוכן, שמות עמודות וערכי עמודות שמשמשים את הטבלאות:
-
טבלה של
ContactsContract.Contacts
- שורות שמייצגות אנשים שונים, על סמך צבירות של שורות גולמיות של אנשי קשר.
-
טבלה של
ContactsContract.RawContacts
- שורות שמכילות סיכום של נתוני אדם, ספציפיים לסוג ולחשבון משתמש.
-
טבלה של
ContactsContract.Data
- שורות שמכילות את הפרטים של איש הקשר הגולמי, כמו כתובות אימייל או מספרי טלפון.
הטבלאות האחרות שמיוצגות על ידי מחלקות חוזים ב-ContactsContract
הן טבלאות עזר שספק אנשי הקשר משתמש בהן כדי לנהל את הפעולות שלו או לתמוך
בפונקציות ספציפיות באפליקציות של אנשי הקשר או הטלפוניה במכשיר.
נתונים גולמיים של אנשי קשר
איש קשר גולמי מייצג את הנתונים של אדם שמגיעים מסוג חשבון אחד ומחשבון אחד. ספק אנשי הקשר מאפשר ליותר משירות אינטרנט אחד לשמש כמקור נתונים של אדם מסוים, ולכן הוא מאפשר כמה אנשי קשר גולמיים לאותו אדם. בנוסף, אפשר לשלב נתונים של אדם מכמה חשבונות מאותו סוג.
רוב הנתונים של איש קשר גולמי לא מאוחסנים בטבלה 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.com
emilyd@gmail.com
- חשבון טוויטר belle_of_amherst
המשתמש הזה הפעיל את האפשרות סנכרון אנשי הקשר לכל שלושת החשבונות האלה בהגדרות החשבונות.
נניח שאמילי דיקינסון פותחת חלון דפדפן, נכנסת ל-Gmail בתור
emily.dickinson@gmail.com
, פותחת את אנשי הקשר ומוסיפה את 'תומס היגינסון'. בהמשך, היא מתחברת ל-Gmail בתור emilyd@gmail.com
ושולחת אימייל ל'Thomas Higginson', שנוסף אוטומטית לאנשי הקשר שלה. היא גם עוקבת אחרי colonel_tom (המזהה של תומס היגינסון ב-Twitter) ב-Twitter.
ספק אנשי הקשר יוצר שלושה אנשי קשר גולמיים כתוצאה מהפעולה הזו:
-
נתונים גולמיים של איש הקשר 'Thomas Higginson' שמשויכים ל-
emily.dickinson@gmail.com
. הסוג של חשבון המשתמש הוא Google. -
איש קשר שני לא מעובד בשם 'Thomas Higginson' שמשויך ל-
emilyd@gmail.com
. סוג חשבון המשתמש הוא גם Google. יש איש קשר גולמי שני, למרות שהשם זהה לשם קודם, כי האדם נוסף לחשבון משתמש אחר. - איש קשר גולמי שלישי בשם Thomas Higginson שמשויך ל-belle_of_amherst. סוג חשבון המשתמש הוא טוויטר.
נתונים
כמו שצוין קודם, הנתונים של איש קשר גולמי מאוחסנים בשורה ContactsContract.Data
שמקושרת לערך _ID
של איש הקשר הגולמי. כך יכול להיות לכל איש קשר גולמי כמה מופעים של אותו סוג נתונים, כמו כתובות אימייל או מספרי טלפון. לדוגמה, אם השורה של איש הקשר הגולמי 'Thomas Higginson' ב-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. הקשרים בין הטבלאות Contacts, Raw Contacts ו-Details.
שימו לב: אם אתם מפרסמים את האפליקציה שלכם בחנות 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 Contacts זהים לחשבונות 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 אם איש הקשר הוא פרופיל המשתמש.
מטא-נתונים של ספק אנשי הקשר
ספק אנשי הקשר מנהל נתונים שעוקבים אחרי מצב הנתונים של אנשי הקשר במאגר. המטא-נתונים האלה לגבי המאגר מאוחסנים במקומות שונים, כולל בשורות של הטבלאות Raw Contacts, Data ו-Contacts, בטבלה 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 |
(הכול) | אפשר להשתמש בטבלה הזו כדי לאחסן מטא-נתונים עבור מתאם הסנכרון. | באמצעות הטבלה הזו אפשר לאחסן את מצב הסנכרון ונתונים אחרים שקשורים לסנכרון באופן קבוע במכשיר. |
גישה לניהול אנשי הקשר
בקטע הזה מפורטות הנחיות לגישה לנתונים מספק אנשי הקשר, עם דגש על הנושאים הבאים:
- שאילתות לגבי ישויות.
- שינוי בכמות גדולה.
- אחזור ושינוי באמצעות כוונות.
- תקינות הנתונים.
בקטע Contacts Provider sync adapters יש פרטים נוספים על ביצוע שינויים באמצעות מתאם סנכרון.
שליחת שאילתות לגבי ישויות
מכיוון שהטבלאות של ספק אנשי הקשר מאורגנות בהיררכיה, לעיתים קרובות כדאי לאחזר שורה ואת כל שורות הצאצא שמקושרות אליה. לדוגמה, כדי להציג את כל המידע על אדם מסוים, יכול להיות שתרצו לאחזר את כל השורות של ContactsContract.RawContacts
עבור שורה אחת של ContactsContract.Contacts
, או את כל השורות של ContactsContract.CommonDataKinds.Email
עבור שורה אחת של ContactsContract.RawContacts
. כדי להקל על כך, ספק אנשי הקשר מציע מבני ישות, שפועלים כמו שאילתות איחוד (join) במסד נתונים בין טבלאות.
ישות היא כמו טבלה שמורכבת מעמודות נבחרות מטבלת האב ומטבלת הצאצא שלה.
כששולחים שאילתה לגבי ישות, מציינים הקרנה וקריטריונים לחיפוש על סמך העמודות שזמינות מהישות. התוצאה היא 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
מפעיל קריאה חוזרת אל
onLoadFinished()
. אחד מהארגומנטים הנכנסים לשיטה הזו הוא
Cursor
עם תוצאות השאילתה. באפליקציה שלכם, תוכלו לקבל את הנתונים מ-Cursor
כדי להציג אותם או לעבוד איתם.
שינוי של כמה קמפיינים בבת אחת
בכל הזדמנות, כדאי להוסיף, לעדכן ולמחוק נתונים ב-Contacts Provider ב'מצב אצווה', על ידי יצירת ArrayList
של אובייקטים מסוג ContentProviderOperation
וקריאה ל-applyBatch()
. כי ספק אנשי הקשר מבצע את כל הפעולות ב-applyBatch()
בעסקה אחת, כך שהשינויים שלכם אף פעם לא יצאו ממאגר אנשי הקשר במצב לא עקבי. שינוי בקבוצה מאפשר גם להוסיף איש קשר גולמי ואת נתוני הפרטים שלו בו-זמנית.
הערה: כדי לשנות איש קשר אחד לא מעובד, כדאי לשלוח intent לאפליקציית אנשי הקשר של המכשיר במקום לטפל בשינוי באפליקציה שלכם. הסבר מפורט על הפעולה הזו מופיע בקטע אחזור ושינוי באמצעות intents.
נקודות עצירה
שינוי בכמות גדולה של פעולות יכול לחסום תהליכים אחרים,
ולגרום לחוויית משתמש גרועה. כדי לארגן את כל השינויים שרוצים לבצע בכמה שפחות רשימות נפרדות, ובמקביל למנוע מהם לחסום את המערכת, צריך להגדיר נקודות ויתור לפעולה אחת או יותר.
נקודת יציאה היא אובייקט ContentProviderOperation
שהערך של isYieldAllowed()
שלו מוגדר כ-true
. כשספק אנשי הקשר נתקל בנקודת עצירה, הוא משהה את הפעולה כדי לאפשר לתהליכים אחרים לפעול, וסוגר את העסקה הנוכחית. כשהספק יתחיל שוב, הוא ימשיך עם הפעולה הבאה ב-ArrayList
ויתחיל טרנזקציה חדשה.
נקודות התפוקה מובילות ליותר מעסקה אחת לכל שיחה אל
applyBatch()
. לכן, כדאי להגדיר נקודת עצירה לפעולה האחרונה עבור קבוצה של שורות קשורות.
לדוגמה, צריך להגדיר נקודת עצירה לפעולה האחרונה בקבוצה שמוסיפה שורות של אנשי קשר גולמיים ושורות של נתונים שקשורים אליהן, או לפעולה האחרונה בקבוצה של שורות שקשורות לאיש קשר יחיד.
נקודות עצירה הן גם יחידה של פעולה אטומית. כל הגישות בין שתי נקודות חזרה יצליחו או ייכשלו כיחידה אחת. אם לא מגדירים נקודות להחזרת נתונים, הפעולה האטומית הקטנה ביותר היא כל אצווה הפעולות. אם משתמשים בנקודות להגדלת נפח התנועה, אפשר למנוע את הפגיעה בביצועי המערכת, ובו-זמנית לוודא שקבוצת משנה של פעולות היא אטומית.
הפניות חוזרות לשינוי
כשמוסיפים שורה חדשה של נתוני איש קשר גולמיים ואת שורות הנתונים המשויכות לה כקבוצה של
אובייקטים מסוג ContentProviderOperation
, צריך לקשר את שורות הנתונים לשורה של נתוני איש הקשר הגולמיים על ידי הוספת הערך _ID
של נתוני איש הקשר הגולמיים כערך RAW_CONTACT_ID
. עם זאת, הערך הזה לא זמין כשיוצרים את ContentProviderOperation
לשורת הנתונים, כי עדיין לא החלתם את ContentProviderOperation
לשורת פרטי הקשר הגולמיים. כדי לעקוף את הבעיה,
במחלקה ContentProviderOperation.Builder
יש את השיטה
withValueBackReference()
.
בשיטה הזו אפשר להוסיף או לשנות עמודה עם התוצאה של פעולה קודמת.
לשיטה withValueBackReference()
יש שני ארגומנטים:
-
key
- המפתח של צמד מפתח/ערך. הערך של הארגומנט הזה צריך להיות שם של עמודה בטבלה שמשנים.
-
previousResult
-
האינדקס של ערך במערך של אובייקטים
ContentProviderResult
מ-applyBatch()
, כשהספירה מתחילה מ-0. במהלך הפעלת הפעולות באצווה, התוצאה של כל פעולה מאוחסנת במערך ביניים של תוצאות. הערך של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());
לאחר מכן, הקוד יוצר שורות נתונים עבור השורות של השם המוצג, הטלפון והאימייל.
כל אובייקט של 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()
. - מחילים את העסקה הקבוצתית.
אם שורה של נתוני איש קשר גולמיים מתעדכנת על ידי פעולה אחרת בין הזמן שבו קראתם את השורה לבין הזמן שבו ניסיתם לשנות אותה, הפעולה 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 לאפליקציית אנשי הקשר של המכשיר מאפשרת גישה עקיפה לספק אנשי הקשר. הכוונה מפעילה את ממשק המשתמש של אפליקציית אנשי הקשר במכשיר, שבו המשתמשים יכולים לבצע פעולות שקשורות לאנשי קשר. עם סוג הגישה הזה, המשתמשים יכולים:
- בוחרים איש קשר מרשימה ומחזירים אותו לאפליקציה כדי להמשיך לעבוד.
- עריכה של נתונים של איש קשר קיים.
- הוספת איש קשר חדש לכל אחד מהחשבונות שלהם.
- מחיקה של איש קשר או של נתונים של אנשי קשר.
אם המשתמש מוסיף או מעדכן נתונים, אפשר לאסוף את הנתונים קודם ולשלוח אותם כחלק מהכוונה.
כשמשתמשים ב-Intents כדי לגשת ל-Contacts Provider דרך אפליקציית אנשי הקשר במכשיר, לא צריך לכתוב ממשק משתמש או קוד משלכם כדי לגשת ל-Provider. בנוסף, לא צריך לבקש הרשאה לקרוא או לכתוב לספק. אפליקציית אנשי הקשר במכשיר יכולה להעניק לכם הרשאת קריאה לאיש קשר, ומכיוון שאתם מבצעים שינויים בספק דרך אפליקציה אחרת, אתם לא צריכים הרשאות כתיבה.
התהליך הכללי של שליחת כוונה (intent) לגישה לספק מתואר בפירוט במדריך
יסודות של ספקי תוכן בקטע 'גישה לנתונים באמצעות כוונות'. בטבלה 4 מופיע סיכום של הפעולה, סוג ה-MIME וערכי הנתונים שבהם משתמשים במשימות הזמינות, וערכי התוספים שאפשר להשתמש בהם עם putExtra()
מפורטים במסמכי העיון של ContactsContract.Intents.Insert
:
טבלה 4. ה-Intents של ספק אנשי הקשר.
משימה | פעולה | נתונים | סוג MIME | הערות |
---|---|---|---|---|
בחירת איש קשר מהרשימה | ACTION_PICK |
אחת מהאפשרויות:
|
לא בשימוש |
הצגת רשימה של אנשי קשר גולמיים או רשימה של נתונים מאנשי קשר גולמיים, בהתאם לסוג ה-URI של התוכן שציינתם.
Call
|
הוספת איש קשר חדש | Insert.ACTION |
לא רלוונטי |
RawContacts.CONTENT_TYPE , סוג MIME של קבוצת אנשי קשר גולמיים.
|
מוצג המסך הוספת איש קשר של אפליקציית אנשי הקשר במכשיר. הערכים של התוספים שמוסיפים ל-intent מוצגים. אם השליחה מתבצעת באמצעות startActivityForResult() , ה-URI של התוכן של איש הקשר הגולמי שנוסף מועבר בחזרה לשיטת הקריאה החוזרת onActivityResult() של הפעילות בארגומנט Intent , בשדה data. כדי לקבל את הערך, קוראים לפונקציה getData() .
|
עריכה של איש קשר | ACTION_EDIT |
CONTENT_LOOKUP_URI לאיש הקשר. הפעילות של העורך תאפשר למשתמש לערוך את כל הנתונים שמשויכים לאיש הקשר הזה.
|
Contacts.CONTENT_ITEM_TYPE , איש קשר אחד. |
המסך 'עריכת איש הקשר' מוצג באפליקציית אנשי הקשר. ערכי התוספים שמוסיפים לכוונת המשתמש מוצגים. כשהמשתמש לוחץ על סיום כדי לשמור את העריכות, הפעילות שלכם חוזרת לחזית. |
הצגת בורר שאפשר להוסיף דרכו גם נתונים. | ACTION_INSERT_OR_EDIT |
לא רלוונטי |
CONTENT_ITEM_TYPE
|
הכוונה הזו תמיד מציגה את מסך הבחירה של אפליקציית אנשי הקשר. המשתמש יכול לבחור איש קשר לעריכה או להוסיף איש קשר חדש. יוצג מסך העריכה או מסך ההוספה, בהתאם לבחירת המשתמש, ויוצגו נתוני התוספים שמועברים ב-Intent. אם האפליקציה מציגה נתוני איש קשר כמו כתובת אימייל או מספר טלפון, צריך להשתמש ב-Intent הזה כדי לאפשר למשתמש להוסיף את הנתונים לאיש קשר קיים.
contact,
הערה: אין צורך לשלוח ערך של שם בתוספים של הכוונה הזו, כי המשתמש תמיד בוחר שם קיים או מוסיף שם חדש. בנוסף, אם שולחים שם והמשתמש בוחר לערוך אותו, אפליקציית אנשי הקשר תציג את השם ששלחתם ותחליף את הערך הקודם. אם המשתמש לא שם לב לזה ושומר את העריכה, הערך הישן יאבד. |
אפליקציית אנשי הקשר במכשיר לא מאפשרת למחוק איש קשר גולמי או נתונים שלו עם כוונה. במקום זאת, כדי למחוק איש קשר גולמי, משתמשים ב-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 מציעה מסגרת אימות שדומה למסגרת של מתאם הסנכרון, ולעתים קרובות משתמשים בה בשילוב עם המסגרת הזו. ה-framework של האימות משתמש במאמתים של תוספים שהם מחלקות משנה של AbstractAccountAuthenticator
. מנגנון אימות מאמת את הזהות של המשתמש בשלבים הבאים:
- התוסף אוסף את השם, הסיסמה או מידע דומה של המשתמש (האישורים של המשתמש).
- שליחת פרטי הכניסה לשירות
- בודק את התשובה של השירות.
אם השירות מקבל את פרטי הכניסה, מאמת החשבונות יכול לאחסן את פרטי הכניסה לשימוש מאוחר יותר. בגלל מסגרת האימות של התוסף, AccountManager
יכול לספק גישה לכל אסימוני האימות שמאמת תומך בהם ובוחר לחשוף, כמו אסימוני אימות של OAuth2.
למרות שאימות לא נדרש, רוב שירותי אנשי הקשר משתמשים בו. עם זאת, לא חייבים להשתמש במסגרת האימות של Android כדי לבצע אימות.
הטמעה של מתאם סנכרון
כדי להטמיע מתאם סנכרון עבור ספק אנשי הקשר, מתחילים ביצירת אפליקציית Android שמכילה את הרכיבים הבאים:
-
רכיב
Service
שמגיב לבקשות מהמערכת להתחבר למתאם הסנכרון. -
כשהמערכת רוצה להפעיל סנכרון, היא קוראת ל-method
onBind()
של השירות כדי לקבלIBinder
עבור מתאם הסנכרון. כך המערכת יכולה לבצע קריאות חוצות תהליכים לשיטות של המתאם. -
מתאם הסנכרון בפועל, שמוטמע כסיווג משנה קונקרטי של
AbstractThreadedSyncAdapter
. -
המחלקות האלה מבצעות את העבודה של הורדת נתונים מהשרת, העלאת נתונים מהמכשיר ופתרון קונפליקטים. הפעולה העיקרית של המתאם מתבצעת בשיטה
onPerformSync()
. צריך ליצור מופע של המחלקה הזו כסינגלטון. -
מחלקה משנית של
Application
. -
המחלק הזה פועל כמפעל עבור סינגלטון של מתאם הסנכרון. משתמשים בשיטה
onCreate()
כדי ליצור מופע של מתאם הסנכרון, ומספקים שיטת getter סטטית כדי להחזיר את הסינגלטון לשיטהonBind()
של שירות מתאם הסנכרון. -
אופציונלי: רכיב
Service
שמגיב לבקשות מהמערכת לאימות משתמשים. -
AccountManager
מתחיל את השירות הזה כדי להתחיל את תהליך האימות. השיטהonCreate()
של השירות יוצרת מופע של אובייקט מאמת. כשהמערכת רוצה לאמת חשבון משתמש עבור מתאם הסנכרון של האפליקציה, היא קוראת לשיטהonBind()
של השירות כדי לקבל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
- מחרוזת טקסט שמכילה את הזמן שבו פריט הנתונים של הפיד נוסף או עודכן, בפורמט של מילישניות מאז ראשית זמן יוניקס. אפליקציות שמוסיפות או מעדכנות פריטים בזרם אחראיות לתחזוקת העמודה הזו. ספק אנשי הקשר לא מתחזק אותה באופן אוטומטי.
כדי להציג מידע מזהה על הפריטים בפיד, צריך להשתמש ב-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
, כדי לאפשר לשירות לקבל כוונות. הנתונים ב-Intent הנכנס מכילים את ה-URI של התוכן של איש הקשר הגולמי שהמשתמש לחץ עליו. משירות ההתראות, אפשר לבצע קישור ואז להפעיל את מתאם הסנכרון כדי לעדכן את הנתונים של איש הקשר הגולמי.
כדי לרשום פעילות שתופעל כשהמשתמש ילחץ על פריט או תמונה בפיד, או על שניהם:
-
יוצרים קובץ בשם
contacts.xml
בספרייהres/xml/
של הפרויקט. אם כבר יש לכם את הקובץ הזה, אתם יכולים לדלג על השלב הזה. -
בקובץ הזה, מוסיפים את הרכיב
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. אם הרכיב הזה כבר קיים, אפשר לדלג על השלב הזה. -
כדי לרשום אחת מהפעילויות שלכם לטיפול בלחיצה של המשתמש על פריט בפיד באפליקציית אנשי הקשר של המכשיר, מוסיפים את המאפיין
viewStreamItemActivity="activityclass"
לרכיב, כאשרactivityclass
הוא שם המחלקה המלא של הפעילות שאמורה לקבל את הכוונה מאפליקציית אנשי הקשר של המכשיר. -
כדי לרשום אחת מהפעילויות שלכם לטיפול בלחיצה של המשתמש על תמונה בפיד באפליקציית אנשי הקשר של המכשיר, מוסיפים את המאפיין
viewStreamItemPhotoActivity="activityclass"
לרכיב, כאשרviewStreamItemPhotoActivity="activityclass"
הוא שם המחלקה המלא של הפעילות שאמורה לקבל את ה-Intent מאפליקציית אנשי הקשר של המכשיר.activityclass
תיאור מפורט יותר של הרכיב <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
הוא מחרוזת טקסט שמוצגת בתפריט הוספת חיבור באפליקציית אנשי הקשר של המכשיר.
הערה: 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
- השם המלא של המחלקה של הפעילות באפליקציה שרוצים להפעיל כשמשתמש בוחר באפשרות הוספת חיבור מאפליקציית אנשי הקשר במכשיר.
inviteContactActionLabel
-
מחרוזת טקסט שמוצגת לפעילות שצוינה ב-
inviteContactActivity
, בתפריט הוספת חיבור. לדוגמה, אפשר להשתמש במחרוזת 'עקוב אחרי ברשת שלי'. אפשר להשתמש במזהה של משאב מחרוזת בשביל התווית הזו. 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, שמתוארת בפירוט בקטע תמונות בפיד של הרשתות החברתיות.