ניהול אנשי הקשר

'ספק אנשי הקשר' הוא רכיב 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, תחילה המשתמש צריך להוסיף את החשבון 'type' (com.example.dataservice) והחשבון 'name' (becky.smart@dataservice.example.com) לפני שהאפליקציה תוכל להוסיף שורות גולמיות של אנשי קשר. אפשר להסביר את הדרישה הזו למשתמש במסמכי העזרה, או לבקש מהמשתמש להוסיף את הסוג והשם, או את שניהם. סוגי חשבונות ושמות חשבונות מתוארים בפירוט בקטע הבא.

מקורות של נתונים גולמיים של אנשי קשר

כדי להבין איך פועלים אנשי הקשר הגולמיים, אפשר להתייחס למשתמש "אמילי דיקינסון" שיש להם את הפרטים הבאים שלושה חשבונות משתמשים שהוגדרו במכשיר שלה:

  • 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.

ספק אנשי הקשר יוצר שלושה אנשי קשר גולמיים כתוצאה מכך:

  1. איש קשר גולמי של "תומס היגינסון" שמשויך אל emily.dickinson@gmail.com. סוג חשבון המשתמש הוא Google.
  2. איש קשר גולמי שני של 'Thomas Higginson' שמשויך ל-emilyd@gmail.com. סוג חשבון המשתמש הוא גם Google. יש איש קשר גולמי שני, למרות שהשם זהה לשם קודם, כי האדם נוסף לחשבון משתמש אחר.
  3. איש קשר גולמי שלישי של "תומס היגינסון" המשויך ל-"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 שמורה לאחסון אובייקט בינארי גדול (Binary Large Object) נתוני (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) והשמות של עמודות ספציפיות לסוג "overlay" שמות העמודות הגנריים

איך שמות של עמודות ספציפיות לסוג מתואמים לשמות של עמודות כלליות

איור 2. שמות עמודות ספציפיים לסוג ושמות עמודות כלליים.

כיתות של שמות עמודות ספציפיות לסוג

טבלה 2 מפרטת את סיווגי השמות הנפוצים ביותר של עמודות לפי סוג:

טבלה 2. כיתות של שמות עמודות ספציפיות לסוג

שיעור מיפוי סוג הנתונים הערות
ContactsContract.CommonDataKinds.StructuredName נתוני השם של איש הקשר הגולמי שמשויך לשורת הנתונים הזו. איש קשר גולמי כולל רק אחת מהשורות האלה.
ContactsContract.CommonDataKinds.Photo התמונה הראשית של איש הקשר הגולמי שמשויך לשורת הנתונים הזו. איש קשר גולמי כולל רק אחת מהשורות האלה.
ContactsContract.CommonDataKinds.Email כתובת אימייל של איש הקשר הגולמי המשויך לשורת הנתונים הזו. לאיש קשר גולמי יכולות להיות מספר כתובות אימייל.
ContactsContract.CommonDataKinds.StructuredPostal כתובת למשלוח דואר של איש הקשר הגולמי המשויך לשורת הנתונים הזו. לאיש קשר גולמי יכולות להיות כמה כתובות למשלוח דואר.
ContactsContract.CommonDataKinds.GroupMembership מזהה שמקשר את איש הקשר הגולמי לאחת מהקבוצות בספק אנשי הקשר. קבוצות הן תכונה אופציונלית של סוג חשבון ושם חשבון. הם מתוארים ב תוכלו למצוא פרטים נוספים בקטע קבוצות של אנשי קשר.

אנשי קשר

הספק של אנשי הקשר משליך את שורות אנשי הקשר הגולמיות מכל סוגי החשבונות ומכל שמות החשבונות כדי ליצור איש קשר. כך קל יותר להציג ולשנות את כל הנתונים שהמשתמש אסף לגבי אדם מסוים. שירות ניהול אנשי הקשר מנהל את היצירה של שורות אנשי קשר חדשות ואת הצבירה של אנשי קשר גולמיים בשורה קיימת של איש קשר. לא אפליקציות ולא מתאמי סנכרון מורשים להוסיף אנשי קשר, ועמודות מסוימות בשורת אנשי קשר מוגדרות לקריאה בלבד.

הערה: אם תנסו להוסיף איש קשר לספק אנשי הקשר עם insert(), תקבלו חריגה מסוג UnsupportedOperationException. אם תנסו לעדכן עמודה שמופיעה בתור 'לקריאה בלבד', המערכת תתעלם מהעדכון.

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

ספק אנשי הקשר מקשר שורה של איש קשר לשורות של אנשי הקשר הגולמיות עם השורה של איש הקשר העמודה _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) ואילך, חשוב לזכור שקבוצה מוגבלת של שדות ושיטות נתונים של אנשי קשר הם מיושנים.

בתנאים שצוינו, המערכת מנקה מדי פעם את הערכים שנכתבו בשדות הנתונים האלה:

גם ממשקי ה-API שמשמשים להגדרת שדות הנתונים שלמעלה לא תקפים יותר:

בנוסף, השדות הבאים לא מחזירים יותר אנשי קשר תדירים. חשוב לזכור שחלק מהשדות האלה משפיעים על הדירוג של אנשי הקשר רק אם אנשי הקשר הם חלק מסוג נתונים ספציפי.

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

כדי לוודא שהפונקציונליות של האפליקציה לא מושפעת מהשינוי הזה, תוכלו לנקות את שדות הנתונים האלה באופן ידני. כדי לעשות זאת, מריצים את ה-ADB הבא פקודה במכשיר שמותקנת בו גרסת Android 4.1 (רמת API 16) ומעלה:

adb shell content delete \
--uri content://com.android.contacts/contacts/delete_usage

נתונים ממתאמי סנכרון

המשתמשים מזינים את פרטי אנשי הקשר ישירות במכשיר, אבל הנתונים עוברים גם לספק אנשי הקשר משירותי אינטרנט באמצעות מתאמי סנכרון, שמבצעים באופן אוטומטי את העברת הנתונים בין המכשיר לשירותים. המתאמים לסנכרון פועלים ברקע בשליטת המערכת, והם קוראים לשיטות ContentResolver לניהול נתונים.

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

סוג חשבון
מזהה שירות שבו המשתמש אחסן נתונים. בדרך כלל, המשתמש צריך לבצע אימות באמצעות השירות. לדוגמה, אנשי הקשר ב-Google הם סוג חשבון שמזוהה באמצעות הקוד google.com. הערך הזה תואם לסוג החשבון שבו משתמשים AccountManager
שם החשבון
מזהה חשבון או כניסה ספציפיים לסוג חשבון. חשבונות אנשי קשר מחשבון Google הם זהים לחשבונות Google עם כתובת אימייל כשם החשבון. שירותים אחרים עשויים להשתמש בשם משתמש בן מילה אחת או במזהה מספרי.

סוגים של חשבונות לא חייבים להיות ייחודיים. משתמש יכול להגדיר כמה חשבונות של אנשי קשר בחשבון Google ולהוריד את הנתונים שלהם לספק אנשי הקשר; מצב כזה יכול לקרות אם למשתמש יש קבוצה אחת של אנשי קשר אישיים לשם חשבון אישי, וקבוצה נוספת לעבודה. שמות החשבונות הם בדרך כלל ייחודיות. יחד, הם מזהים תעבורת נתונים ספציפית בין ספק אנשי הקשר לבין שירות חיצוני.

אם אתם רוצים להעביר את הנתונים של השירות שלכם לספק אנשי הקשר, תצטרכו לכתוב מתאם סנכרון משלכם. הנושא הזה מוסבר בפירוט בקטע מתאמי סנכרון של ספקי אנשי קשר.

באיור 4 מוצגת ההתאמה של ספק אנשי הקשר לזרימת הנתונים על אנשים. בתיבה 'מתאמי סנכרון', כל מתאם מסומן לפי סוג החשבון שלו.

זרימת נתונים על אנשים

איור 4. תהליך העברת הנתונים של 'ניהול אנשי הקשר'.

הרשאות נדרשות

אפליקציות שרוצות לגשת לספק אנשי הקשר חייבות לבקש את הפרטים הבאים הרשאות:

הרשאת קריאה לטבלה אחת או יותר
READ_CONTACTS, מצוין ב AndroidManifest.xml עם רכיב <uses-permission> בתור <uses-permission android:name="android.permission.READ_CONTACTS">
הרשאת כתיבה לטבלה אחת או יותר
WRITE_CONTACTS, שצוין ב-AndroidManifest.xml עם רכיב <uses-permission> בתור <uses-permission android:name="android.permission.WRITE_CONTACTS">.

ההרשאות האלה לא חלות על הנתונים בפרופיל המשתמש. פרופיל המשתמש והתוכן שלו ההרשאות הנדרשות מתוארות בקטע הבא, פרופיל המשתמש.

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

פרופיל המשתמש

הטבלה ContactsContract.Contacts כוללת שורה אחת שמכילה של המשתמש במכשיר. בנתונים האלה מתואר user של המכשיר מאנשי הקשר של המשתמש. השורה של אנשי הקשר בפרופיל מקושרת לשורה של אנשי קשר גולמיים בכל מערכת שמשתמשת בפרופיל. כל שורה גולמית של איש קשר של פרופיל יכולה לכלול מספר שורות נתונים. תנאים קבועים לגישה למשתמש זמינים בכיתה ContactsContract.Profile.

כדי לגשת לפרופיל המשתמש נדרשות הרשאות מיוחדות. בנוסף להרשאות READ_CONTACTS ו-WRITE_CONTACTS שנדרשות לקריאה ולכתיבה, כדי לגשת לפרופיל המשתמש נדרשות ההרשאות android.Manifest.permission#READ_PROFILE ו-android.Manifest.permission#WRITE_PROFILE לקריאה ולכתיבה, בהתאמה.

חשוב לזכור שפרופיל של משתמש נחשב כמידע אישי רגיש. ההרשאה android.Manifest.permission#READ_PROFILE מאפשרת לך לגשת אל נתונים שמאפשרים זיהוי אישי. צריך להסביר למשתמשים למה נדרשות הרשאות גישה לפרופיל המשתמש בתיאור האפליקציה.

כדי לאחזר את שורת איש הקשר שמכילה את הפרופיל של המשתמש, צריך להפעיל את הפונקציה ContentResolver.query(). הגדרת ה-URI של התוכן כ- CONTENT_URI ולא מספקים קריטריונים לבחירה. ניתן גם להשתמש ב-URI של תוכן זה בתור ה-URI הבסיסי לאחזור גולמיים אנשי הקשר או הנתונים של הפרופיל. לדוגמה, קטע הקוד הבא מאחזר נתונים עבור הפרופיל:

Kotlin

// Sets the columns to retrieve for the user profile
projection = arrayOf(
        ContactsContract.Profile._ID,
        ContactsContract.Profile.DISPLAY_NAME_PRIMARY,
        ContactsContract.Profile.LOOKUP_KEY,
        ContactsContract.Profile.PHOTO_THUMBNAIL_URI
)

// Retrieves the profile from the Contacts Provider
profileCursor = contentResolver.query(
        ContactsContract.Profile.CONTENT_URI,
        projection,
        null,
        null,
        null
)

Java

// Sets the columns to retrieve for the user profile
projection = new String[]
    {
        Profile._ID,
        Profile.DISPLAY_NAME_PRIMARY,
        Profile.LOOKUP_KEY,
        Profile.PHOTO_THUMBNAIL_URI
    };

// Retrieves the profile from the Contacts Provider
profileCursor =
        getContentResolver().query(
                Profile.CONTENT_URI,
                projection ,
                null,
                null,
                null);

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

מטא-נתונים של ניהול אנשי הקשר

ספק אנשי הקשר מנהל נתונים שעוקבים אחרי המצב של נתוני אנשי הקשר בחשבון של מאגר הנתונים. המטא-נתונים האלה לגבי המאגר מאוחסנים במקומות שונים, כולל השורות בטבלאות Raw Contacts‏, Data ו-Contacts, בטבלה ContactsContract.Settings ובטבלה ContactsContract.SyncState. הטבלה הבאה מציגה את ההשפעה של כל אחד מקטעי המטא-נתונים האלה:

טבלה 3 מטא-נתונים בספק אנשי הקשר

טבלה עמודה ערכים משמעות
ContactsContract.RawContacts DIRTY '0' – לא השתנה מאז הסנכרון האחרון. סימון של אנשי קשר גולמיים שהשתנו במכשיר וצריכים להסתנכרן חזרה עם השרת. הערך מוגדר באופן אוטומטי על ידי ספק אנשי הקשר ב-Android מתעדכנות שורה.

מתאמי סנכרון שמשנים את הנתונים הגולמיים של אנשי הקשר או טבלאות הנתונים תמיד צריכים להוסיף מחרוזת CALLER_IS_SYNCADAPTER ב-URI של התוכן שבו הם משתמשים. כך הספק לא יוכל לסמן שורות כ'לא נקיות'. אחרת, שינויים במתאם הסנכרון נראים כמו שינויים מקומיים שנשלחו לשרת, למרות שהשרת היה מקור השינוי.

'1' – השתנה מאז הסנכרון האחרון, צריך לסנכרן אותו חזרה לשרת.
ContactsContract.RawContacts VERSION מספר הגרסה של השורה הזו. 'ספק אנשי הקשר' מגדיל את הערך הזה באופן אוטומטי בכל פעם שהשורה או שינויים בנתונים שקשורים אליו.
ContactsContract.Data DATA_VERSION מספר הגרסה של השורה הזו. 'ספק אנשי הקשר' מגדיל את הערך הזה באופן אוטומטי בכל פעם ששורת הנתונים משתנה.
ContactsContract.RawContacts SOURCE_ID ערך מחרוזת שמזהה באופן ייחודי את איש הקשר הגולמי הזה עם החשבון שבה הוא נוצר. כשמתאם סנכרון יוצר איש קשר חדש בפורמט גולמי, צריך להגדיר בעמודה הזו את המזהה הייחודי של איש הקשר בפורמט גולמי בשרת. כשאפליקציה ל-Android יוצרת אפליקציה חדשה איש קשר גולמי, האפליקציה צריכה להשאיר את העמודה הזו ריקה. הפעולה הזו מאותתת למתאם הסנכרון שהוא צריך ליצור איש קשר חדש בפורמט גולמי בשרת ולקבל ערך בשדה SOURCE_ID.

באופן ספציפי, מזהה המקור חייב להיות ייחודי לכל חשבון מסוג והוא צריך להיות יציב בכל סנכרונים:

  • ייחודי: לכל איש קשר גולמי בחשבון חייב להיות מזהה מקור משלו. אם לא יאכפו את הכלל הזה, יהיו בעיות באפליקציית אנשי הקשר. חשוב לזכור שלשני אנשי קשר גולמיים באותו סוג של חשבון יכול להיות אותו מזהה מקור. לדוגמה, איש הקשר הגולמי "תומס היגינסון" עבור לחשבון emily.dickinson@gmail.com יכול להיות אותו מקור מזהה בתור איש הקשר הגולמי "תומס היגינסון" לחשבון emilyd@gmail.com.
  • יציב: מזהי המקור הם חלק קבוע מהנתונים של השירות אונליין לגבי איש הקשר הגולמי. לדוגמה, אם המשתמש מנקה את האחסון של אנשי הקשר בהגדרות האפליקציות ומבצע סנכרון מחדש, לאנשי הקשר הגולמיים המשוחזרים אמורים להיות אותם מזהי מקור כמו קודם. אם לא תתבצע אכיפה של ההגדרה הזו, קיצורי הדרך יפסיקו לפעול עובדת.
ContactsContract.Groups GROUP_VISIBLE '0' – אנשי הקשר בקבוצה הזו לא אמורים להיות גלויים בממשקי המשתמש של אפליקציות ל-Android. העמודה הזו מיועדת לתאימות לשרתים שמאפשרים למשתמש להסתיר אנשי קשר קבוצות מסוימות.
'1' - אנשי הקשר בקבוצה הזו יכולים להופיע בממשקי המשתמש של האפליקציה.
ContactsContract.Settings UNGROUPED_VISIBLE '0' – בחשבון הזה ובסוג החשבון הזה, אנשי קשר שלא שייכים לקבוצה לא גלויים לממשקי המשתמש של אפליקציות ל-Android. כברירת מחדל, אנשי קשר לא גלויים אם אף אחד מאנשי הקשר הגולמיים שלהם לא שייך לקבוצה (השתייכות לקבוצה של איש קשר גולמי מסומן בשורה אחת או יותר של ContactsContract.CommonDataKinds.GroupMembership בטבלה ContactsContract.Data). על ידי הגדרת הדגל הזה בשורה ContactsContract.Settings בטבלה עבור סוג חשבון וחשבון, ניתן לאלץ אנשי קשר ללא קבוצות להיות גלויים. אחת מהשימושים בדגל הזה היא להציג אנשי קשר משרתי אימייל שלא משתמשים בקבוצות.
'1' – בחשבון הזה ובסוג החשבון הזה, אנשי קשר שלא שייכים לקבוצה גלויים לממשקי המשתמש של האפליקציות.
ContactsContract.SyncState (הכול) אפשר להשתמש בטבלה הזו כדי לאחסן מטא-נתונים של מתאם הסנכרון. בעזרת הטבלה הזו ניתן לאחסן באופן קבוע את מצב הסנכרון ונתונים אחרים שקשורים לסנכרון במכשיר.

גישת ספק לאנשי הקשר

בקטע הזה מפורטות הנחיות לגישה לנתונים מספק אנשי הקשר, עם דגש על הנושאים הבאים:

  • שאילתות על ישויות.
  • שינוי קבוצתי.
  • אחזור ושינוי של כוונות.
  • תקינות הנתונים.

אפשר לקרוא מידע נוסף על ביצוע שינויים באמצעות מתאם סנכרון בקטע מתאמי סנכרון של ספקי אנשי קשר.

ישויות שליחת שאילתות

בגלל שהטבלאות של 'ספקי אנשי קשר' מאורגנות בהיררכיה, מומלץ בדרך כלל מאחזרים שורה ואת כל הנתונים של 'child'. השורות שמקושרות אליו. לדוגמה, כדי להציג את כל המידע עבור אדם, ייתכן שתרצו לאחזר את כל הנתונים ContactsContract.RawContacts שורות לפריט יחיד שורה אחת (ContactsContract.Contacts) או כל ContactsContract.CommonDataKinds.Email שורות לפריט יחיד שורה ContactsContract.RawContacts. כדי לאפשר זאת, ספק אנשי הקשר מציע מבנים של ישויות, שמשמשים כאיחודים של מסדי נתונים בין טבלאות.

ישות היא כמו טבלה המורכבת מעמודות שנבחרו מטבלת הורה ומהטבלה הצאצאית שלה. כשמריצים שאילתה על ישות, צריך לספק תחזית וקריטריונים לחיפוש על סמך העמודות זמינים מהישות. התוצאה היא Cursor שמכיל שורה אחת לכל שורה של טבלת צאצא שאוחזרה. לדוגמה, אם שולחים שאילתה ל-ContactsContract.Contacts.Entity עם שם של איש קשר וכל השורות של ContactsContract.CommonDataKinds.Email עם כל אנשי הקשר הגולמיים של השם הזה, מקבלים חזרה Cursor שמכיל שורה אחת לכל שורה של ContactsContract.CommonDataKinds.Email.

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

הערה: בדרך כלל ישות לא מכילה את כל העמודות של טבלת ההורה וטבלת הצאצא. אם מנסים לעבוד עם שם עמודה שלא מופיע ברשימת הקבועים של שמות העמודות של הישות, מופיעה הערך Exception.

קטע הקוד הבא מראה איך לאחזר את כל שורות איש הקשר הגולמיות של איש קשר. קטע הקוד חלק מיישום גדול יותר שכולל שתי פעילויות, "העיקרית" ו'פירוט'. הפעילות העיקרית מציגה רשימה של שורות אנשי קשר. כשהמשתמש יבחר אחת, הפעילות תשלח את המזהה שלה לפרטים פעילות. הפעילות המפורטות משתמשת ב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.
}

כשהטעינה תסתיים, תתבצע קריאה חוזרת (callback) של LoaderManager אל onLoadFinished(). אחד מהארגומנטים הנכנסים לשיטה הזו הוא Cursor עם תוצאות השאילתה. באפליקציה שלכם אפשר לקבל את נתונים מהCursor הזה כדי להציג אותו או כדי להמשיך לעבוד איתו.

שינוי של מספר פריטים בו-זמנית

כשאפשר, כדאי להוסיף, לעדכן ולמחוק נתונים ב'ספק אנשי הקשר' ב 'מצב אצווה', על ידי יצירת ArrayList של ContentProviderOperation אובייקטים ושיחות applyBatch(). כי ספק אנשי הקשר מבצע את כל הפעולות applyBatch() בסינגל טרנזקציה, השינויים שלך אף פעם לא ישאירו את מאגר אנשי הקשר . שינוי בכמות גדולה מאפשר גם להוסיף בו-זמנית איש קשר בסיסי ואת פרטיו המפורטים.

הערה: כדי לשנות איש קשר גולמי יחיד, מומלץ לשלוח כוונה (intent) לאפליקציית אנשי הקשר של המכשיר במקום לטפל בשינוי באפליקציה שלכם. אפשר לקרוא הסבר מפורט יותר בקטע אחזור ושינוי באמצעות כוונות.

נקודות עצירה

שינוי באצווה שמכיל מספר גדול של פעולות עלול לחסום תהליכים אחרים, וכתוצאה מכך חוויית המשתמש הכוללת תהיה גרועה. כדי לארגן את כל השינויים שרוצים בכמה שפחות רשימות נפרדות, ובו-זמנית למנוע אותן וחסימת המערכת, עליך להגדיר נקודות תפוקה לפעולה אחת או יותר. נקודת תפוקה היא אובייקט ContentProviderOperation שקיבל הערך של isYieldAllowed() הוגדר כ- true. כשהספק של אנשי הקשר נתקל בנקודת תפוקה, הוא משהה את העבודה עד מאפשרים לתהליכים אחרים להריץ את העסקה הנוכחית וסוגרים את העסקה. כשהספק יתחיל לפעול שוב, ממשיך בפעולה הבאה ב-ArrayList ומתחילה פעולה חדשה העסקה.

נקודות התשואה כן מניבות יותר מעסקה אחת לכל קריאה ל-applyBatch(). בגלל לכן צריך להגדיר נקודת תפוקה לפעולה האחרונה עבור קבוצה של שורות קשורות. לדוגמה, צריך להגדיר נקודת יעד לפעולה האחרונה בקבוצה שמוסיפה שורות של אנשי קשר גולמיים ושורות הנתונים המשויכות שלהם, או לפעולה האחרונה בקבוצת שורות שקשורות לאיש קשר יחיד.

נקודות עצירה הן גם יחידה של פעולה אטומית. כל הגישה בין שתי נקודות תשואה תצליח או תיכשל כיחידה אחת. אם לא מגדירים נקודות ייצור, הפעולה האטומית הקטנה ביותר היא כל קבוצת הפעולות. אם בכל זאת משתמשים בנקודות תפוקה, מפני ירידה בביצועי המערכת, ובו-זמנית להבטיח שתת-קבוצה של הוא אטומי.

שינוי הפניות קודמות

כשמוסיפים שורה גולמית חדשה של איש קשר ואת שורות הנתונים שמשויכות אליה, כקבוצה של ContentProviderOperation אובייקטים, יש לקשר את שורות הנתונים אל את שורת איש הקשר הגולמית על ידי הוספת נתוני איש הקשר הגולמיים ערך של _ID בתור ערך RAW_CONTACT_ID. עם זאת, הערך הזה לא זמין כשיוצרים את ContentProviderOperation בשורה של הנתונים, כי עדיין לא החילו את ContentProviderOperation על שורת איש הקשר הגולמי. כדי לעקוף את הבעיה, למחלקה ContentProviderOperation.Builder יש את ה-method withValueBackReference(). השיטה הזו מאפשרת להוסיף או לשנות עמודה עם התוצאה של פעולה קודמת.

withValueBackReference() ל-method יש שני ארגומנטים:

key
המפתח של צמד מפתח/ערך. הערך של הארגומנט הזה צריך להיות שם של עמודה בטבלה שאתם משנים.
previousResult
האינדקס שמתחיל בספרה אפס של ערך במערך של אובייקטים מסוג ContentProviderResult מ-applyBatch(). כשמפעילים את פעולות האצווה, התוצאה של כל פעולה מאוחסנת במערך ביניים של תוצאות. הערך של previousResult הוא האינדקס של אחת מהתוצאות האלה, שמאוחזר ונשמר עם הערך של key. פעולה זו מאפשרת לך להוסיף רשומה גולמית חדשה של איש קשר ולחזור _ID, ולאחר מכן ליצור הפניה חזרה ל כשמוסיפים שורה ContactsContract.Data.

מערך התוצאות כולו נוצר בקריאה הראשונה ל-applyBatch(), בגודל שווה לגודל של ArrayList של אובייקטי ContentProviderOperation שסיפקתם. אבל, כל הרכיבים במערך התוצאות מוגדרים ל-null, ואם תנסו כדי לבצע הפניה חזרה לתוצאה של פעולה שעדיין לא הוחלה, withValueBackReference() זורקת Exception.

קטעי הקוד הבאים מראים איך להוסיף באצווה נתונים ואיש קשר גולמיים חדשים. הם כוללים קוד שמגדיר נקודת כניעה ומשתמש בהפניה לאחור.

קטע הקוד הראשון מאחזר את פרטי הקשר מממשק המשתמש. בשלב הזה, המשתמש כבר נבחר החשבון שעבורו יש להוסיף את איש הקשר הגולמי החדש.

Kotlin

// Creates a contact entry from the current UI values, using the currently-selected account.
private fun createContactEntry() {
    /*
     * Gets values from the UI
     */
    val name = contactNameEditText.text.toString()
    val phone = contactPhoneEditText.text.toString()
    val email = contactEmailEditText.text.toString()

    val phoneType: String = contactPhoneTypes[mContactPhoneTypeSpinner.selectedItemPosition]

    val emailType: String = contactEmailTypes[mContactEmailTypeSpinner.selectedItemPosition]

Java

// Creates a contact entry from the current UI values, using the currently-selected account.
protected void createContactEntry() {
    /*
     * Gets values from the UI
     */
    String name = contactNameEditText.getText().toString();
    String phone = contactPhoneEditText.getText().toString();
    String email = contactEmailEditText.getText().toString();

    int phoneType = contactPhoneTypes.get(
            contactPhoneTypeSpinner.getSelectedItemPosition());

    int emailType = contactEmailTypes.get(
            contactEmailTypeSpinner.getSelectedItemPosition());

קטע הקוד הבא יוצר פעולה להוספת שורת איש הקשר הגולמי לטבלה ContactsContract.RawContacts:

Kotlin

    /*
     * Prepares the batch operation for inserting a new raw contact and its data. Even if
     * the Contacts Provider does not have any data for this person, you can't add a Contact,
     * only a raw contact. The Contacts Provider will then add a Contact automatically.
     */

    // Creates a new array of ContentProviderOperation objects.
    val ops = arrayListOf<ContentProviderOperation>()

    /*
     * Creates a new raw contact with its account type (server type) and account name
     * (user's account). Remember that the display name is not stored in this row, but in a
     * StructuredName data row. No other data is required.
     */
    var op: ContentProviderOperation.Builder =
            ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                    .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.name)
                    .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.type)

    // Builds the operation and adds it to the array of operations
    ops.add(op.build())

Java

    /*
     * Prepares the batch operation for inserting a new raw contact and its data. Even if
     * the Contacts Provider does not have any data for this person, you can't add a Contact,
     * only a raw contact. The Contacts Provider will then add a Contact automatically.
     */

     // Creates a new array of ContentProviderOperation objects.
    ArrayList<ContentProviderOperation> ops =
            new ArrayList<ContentProviderOperation>();

    /*
     * Creates a new raw contact with its account type (server type) and account name
     * (user's account). Remember that the display name is not stored in this row, but in a
     * StructuredName data row. No other data is required.
     */
    ContentProviderOperation.Builder op =
            ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
            .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.getType())
            .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.getName());

    // Builds the operation and adds it to the array of operations
    ops.add(op.build());

בשלב הבא, הקוד יוצר שורות נתונים לשורות של השם המוצג, הטלפון וכתובת האימייל.

כל אובייקט של בונה הפעולות משתמש withValueBackReference() כדי לקבל RAW_CONTACT_ID. נקודות ההתייחסות חזרה לאובייקט ContentProviderResult מהפעולה הראשונה, שמוסיפה את השורה הגולמית של איש הקשר ומחזירה את הערך החדש _ID עם ערך מסוים. כתוצאה מכך, כל שורת נתונים מקושרת באופן אוטומטי לפי הערך שלה בשדה RAW_CONTACT_ID לשורת ContactsContract.RawContacts החדשה שאליה היא שייכת.

האובייקט ContentProviderOperation.Builder שמוסיף את שורת האימייל הוא מסומנת באמצעות withYieldAllowed(), שמגדירה נקודת תפוקה:

Kotlin

    // Creates the display name for the new raw contact, as a StructuredName data row.
    op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            /*
             * withValueBackReference sets the value of the first argument to the value of
             * the ContentProviderResult indexed by the second argument. In this particular
             * call, the raw contact ID column of the StructuredName data row is set to the
             * value of the result returned by the first operation, which is the one that
             * actually adds the raw contact row.
             */
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

            // Sets the data row's MIME type to StructuredName
            .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)

            // Sets the data row's display name to the name in the UI.
            .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name)

    // Builds the operation and adds it to the array of operations
    ops.add(op.build())

    // Inserts the specified phone number and type as a Phone data row
    op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            /*
             * Sets the value of the raw contact id column to the new raw contact ID returned
             * by the first operation in the batch.
             */
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

            // Sets the data row's MIME type to Phone
            .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)

            // Sets the phone number and type
            .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
            .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType)

    // Builds the operation and adds it to the array of operations
    ops.add(op.build())

    // Inserts the specified email and type as a Phone data row
    op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            /*
             * Sets the value of the raw contact id column to the new raw contact ID returned
             * by the first operation in the batch.
             */
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

            // Sets the data row's MIME type to Email
            .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)

            // Sets the email address and type
            .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email)
            .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType)

    /*
     * Demonstrates a yield point. At the end of this insert, the batch operation's thread
     * will yield priority to other threads. Use after every set of operations that affect a
     * single contact, to avoid degrading performance.
     */
    op.withYieldAllowed(true)

    // Builds the operation and adds it to the array of operations
    ops.add(op.build())

Java

    // Creates the display name for the new raw contact, as a StructuredName data row.
    op =
            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            /*
             * withValueBackReference sets the value of the first argument to the value of
             * the ContentProviderResult indexed by the second argument. In this particular
             * call, the raw contact ID column of the StructuredName data row is set to the
             * value of the result returned by the first operation, which is the one that
             * actually adds the raw contact row.
             */
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

            // Sets the data row's MIME type to StructuredName
            .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)

            // Sets the data row's display name to the name in the UI.
            .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name);

    // Builds the operation and adds it to the array of operations
    ops.add(op.build());

    // Inserts the specified phone number and type as a Phone data row
    op =
            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            /*
             * Sets the value of the raw contact id column to the new raw contact ID returned
             * by the first operation in the batch.
             */
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

            // Sets the data row's MIME type to Phone
            .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)

            // Sets the phone number and type
            .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
            .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType);

    // Builds the operation and adds it to the array of operations
    ops.add(op.build());

    // Inserts the specified email and type as a Phone data row
    op =
            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            /*
             * Sets the value of the raw contact id column to the new raw contact ID returned
             * by the first operation in the batch.
             */
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

            // Sets the data row's MIME type to Email
            .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)

            // Sets the email address and type
            .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email)
            .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType);

    /*
     * Demonstrates a yield point. At the end of this insert, the batch operation's thread
     * will yield priority to other threads. Use after every set of operations that affect a
     * single contact, to avoid degrading performance.
     */
    op.withYieldAllowed(true);

    // Builds the operation and adds it to the array of operations
    ops.add(op.build());

בקטע הקוד האחרון מוצגת הקריאה ל-applyBatch() שמוסיפה את שורות הנתונים ואנשי הקשר הגולמיים החדשים.

Kotlin

    // Ask the Contacts Provider to create a new contact
    Log.d(TAG, "Selected account: ${mSelectedAccount.name} (${mSelectedAccount.type})")
    Log.d(TAG, "Creating contact: $name")

    /*
     * Applies the array of ContentProviderOperation objects in batch. The results are
     * discarded.
     */
    try {
        contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)
    } catch (e: Exception) {
        // Display a warning
        val txt: String = getString(R.string.contactCreationFailure)
        Toast.makeText(applicationContext, txt, Toast.LENGTH_SHORT).show()

        // Log exception
        Log.e(TAG, "Exception encountered while inserting contact: $e")
    }
}

Java

    // Ask the Contacts Provider to create a new contact
    Log.d(TAG,"Selected account: " + selectedAccount.getName() + " (" +
            selectedAccount.getType() + ")");
    Log.d(TAG,"Creating contact: " + name);

    /*
     * Applies the array of ContentProviderOperation objects in batch. The results are
     * discarded.
     */
    try {

            getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
    } catch (Exception e) {

            // Display a warning
            Context ctx = getApplicationContext();

            CharSequence txt = getString(R.string.contactCreationFailure);
            int duration = Toast.LENGTH_SHORT;
            Toast toast = Toast.makeText(ctx, txt, duration);
            toast.show();

            // Log exception
            Log.e(TAG, "Exception encountered while inserting contact: " + e);
    }
}

פעולות באצווה מאפשרות גם להטמיע בקרה אופטימיסטית על בו-זמניות, שיטה להחיל עסקאות שינוי בלי לנעול את המאגר הבסיסי. כדי להשתמש בשיטה הזו, מחילים את העסקה ואז בודקים אם בוצעו בו-זמנית שינויים אחרים. אם תגלה שינוי לא עקבי, לבטל את העסקה ולנסות שוב.

בקרת בו-זמניות אופטימית שימושית למכשירים ניידים, שבהם יש רק משתמש אחד מספר מסוים של פעמים, והגישה למאגר הנתונים בו-זמנית היא נדירות. כי לא נעשה שימוש בנעילה, לא מתבזבז זמן על הגדרת נעילות או בהמתנה עד שעסקאות אחרות ישוחררו.

כדי להשתמש בבקרת בו-זמניות אופטימית בזמן עדכון בשורה ContactsContract.RawContacts, יש לבצע את השלבים הבאים:

  1. אחזור VERSION של איש הקשר הגולמי יחד עם הנתונים האחרים שאתם מאחזרים.
  2. יצירת אובייקט ContentProviderOperation.Builder שמתאים ל: לאכוף אילוץ באמצעות השיטה, newAssertQuery(Uri). עבור ה-URI של התוכן, להשתמש ב-RawContacts.CONTENT_URI שמוצמד אליו ה-_ID של איש הקשר הגולמי.
  3. בשביל האובייקט ContentProviderOperation.Builder, קוראים withValue() כדי להשוות אל VERSION למספר הגרסה שאחזרת עכשיו.
  4. לאותו ContentProviderOperation.Builder, צריך להפעיל את withExpectedCount() כדי לוודא שרק שורה אחת נבדקת על ידי ההצהרה הזו.
  5. קוראים אל build() כדי ליצור את האובייקט ContentProviderOperation, ואז להוסיף אותו בתור האובייקט הראשון בArrayList שאליו מעבירים applyBatch()
  6. מחילים את העסקה באצווה.

אם השורה הגולמית של איש הקשר מתעדכנת על ידי פעולה אחרת בין מועד קריאת השורה הזמן שבו תנסה לשנות אותו, "הטענה" ContentProviderOperation תיכשל, וכל הפעולות של כל הפעולות יגובו. לאחר מכן תוכלו לנסות שוב את האצווה או לבצע פעולה אחרת.

קטע הקוד הבא מדגים איך יוצרים 'הצהרה על זכויות יוצרים' 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
    }

אחזור ושינוי באמצעות כוונות

שליחת כוונה לאפליקציית אנשי הקשר של המכשיר מאפשרת לכם לגשת לספק אנשי הקשר באופן עקיף. הכוונה מפעילה את ממשק המשתמש של אפליקציית אנשי הקשר במכשיר, שבו המשתמשים יכולים לבצע פעולות שקשורות לאנשי הקשר. עם סוג הגישה הזה, המשתמשים יכולים:

  • בוחרים איש קשר מהרשימה ומחזירים אותו לאפליקציה להמשך העבודה.
  • לערוך את הפרטים של איש קשר קיים.
  • להוסיף איש קשר חדש ללא עיבוד לכל אחד מהחשבונות שלהם.
  • מחיקה של איש קשר או של נתוני אנשי קשר.

אם המשתמש מוסיף או מעדכן נתונים, אפשר לאסוף את הנתונים קודם ולשלוח אותם בפורמט מכוונה.

כשמשתמשים בכוונות כדי לגשת לספק אנשי הקשר דרך אפליקציית אנשי הקשר של המכשיר, לא צריכים לכתוב ממשק משתמש או קוד משלכם כדי לגשת לספק. בנוסף, לא צריך לבקש הרשאה לקריאה או לכתיבה לספק. אפליקציית אנשי הקשר של המכשיר יכולה להעניק לכם הרשאת קריאה של איש קשר מסוים, ובגלל שאתם מבצעים שינויים באמצעות אפליקציה אחרת, אין צורך בהרשאות כתיבה.

התהליך הכללי של שליחת כוונה לגשת לספק מתואר בפירוט המדריך הבסיסי לספקי תוכן בקטע 'גישה לנתונים באמצעות כוונות'. הפעולה, סוג ה-MIME וערכים של נתונים שבהם משתמשים במשימות הזמינות מפורטים בטבלה 4, ואילו הערכים הנוספים שבהם אפשר להשתמש עם putExtra() מפורטים במסמכי העזרה של ContactsContract.Intents.Insert:

טבלה 4. כוונות של ספק אנשי קשר.

משימה פעולה נתונים סוג MIME הערות
בחירת איש קשר מתוך רשימה ACTION_PICK אחת מהאפשרויות: צולם בלי מבזק מציגה רשימה של אנשי קשר גולמיים או רשימת נתונים מאיש קשר גולמי, בהתאם סוג ה-URI של התוכן שסיפקתם.

שיחת טלפון startActivityForResult(), שמחזיר את ה-URI של התוכן של השורה שנבחרה. פורמט ה-URI הוא ה-URI של תוכן הטבלה עם ה-LOOKUP_ID של השורה שמצורף אליו. אפליקציית אנשי הקשר במכשיר מעבירה את הרשאות הקריאה והכתיבה ל-URI של התוכן הזה למשך כל תקופת הפעילות. לצפייה המדריך הבסיסי על ספקי תוכן לקבלת פרטים נוספים.

הוספת איש קשר גולמי חדש Insert.ACTION לא רלוונטי RawContacts.CONTENT_TYPE, סוג MIME לקבוצת אנשי קשר גולמיים. המסך הוספת איש קשר באפליקציית אנשי הקשר של המכשיר מוצג. ערכי התוספות שהוספת ל-Intent מוצגים. אם שולחים את הבקשה עם startActivityForResult(), ה-URI של התוכן של איש הקשר הגולמי שנוסף מחדש מועבר בחזרה לשיטת ה-callback‏ onActivityResult() של הפעילות, בארגומנט Intent, בשדה data. כדי לקבל את הערך, קוראים לפונקציה getData().
עריכת איש קשר ACTION_EDIT CONTENT_LOOKUP_URI עבור איש הקשר. פעילות העורך תאפשר למשתמש לערוך את כל הנתונים המשויכים עם איש הקשר הזה. Contacts.CONTENT_ITEM_TYPE, איש קשר יחיד. מציג את המסך 'עריכת איש קשר' באפליקציית אנשי הקשר. מוצגים הערכים הנוספים שמוסיפים לכוונה. כשהמשתמש לוחץ על סיום כדי לשמור את העריכות, הפעילות חוזרת לחזית.
הצגת בורר שאפשר להשתמש בו גם להוספת נתונים. ACTION_INSERT_OR_EDIT לא רלוונטי CONTENT_ITEM_TYPE כוונת החיפוש הזו תמיד מציגה את מסך הבחירה של אפליקציית אנשי הקשר. המשתמש יכול בוחרים איש קשר לעריכה, או מוסיפים איש קשר חדש. עריכה או הוספה של מסך מוצגות, בהתאם לבחירה של המשתמש, ולנתוני התוספות שאתם מעבירים מוצגת. אם באפליקציה מוצגים פרטים ליצירת קשר כמו כתובת אימייל או מספר טלפון, אפשר להשתמש בכוונה הזו כדי לאפשר למשתמש להוסיף את הפרטים לאיש קשר קיים. איש קשר,

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

אפליקציית 'אנשי קשר' במכשיר לא מאפשרת למחוק איש קשר גולמי או את הנתונים שלו עם בכוונה טובה. במקום זאת, כדי למחוק איש קשר בפורמט גולמי, משתמשים ב-ContentResolver.delete() או ב-ContentProviderOperation.newDelete().

קטע הקוד הבא מראה איך ליצור ולשלוח אובייקט Intent שמוסיף נתוני גולמיים חדשים. איש קשר ונתונים:

Kotlin

// Gets values from the UI
val name = contactNameEditText.text.toString()
val phone = contactPhoneEditText.text.toString()
val email = contactEmailEditText.text.toString()

val company = companyName.text.toString()
val jobtitle = jobTitle.text.toString()

/*
 * Demonstrates adding data rows as an array list associated with the DATA key
 */

// Defines an array list to contain the ContentValues objects for each row
val contactData = arrayListOf<ContentValues>()

/*
 * Defines the raw contact row
 */

// Sets up the row as a ContentValues object
val rawContactRow = ContentValues().apply {
    // Adds the account type and name to the row
    put(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.type)
    put(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.name)
}

// Adds the row to the array
contactData.add(rawContactRow)

/*
 * Sets up the phone number data row
 */

// Sets up the row as a ContentValues object
val phoneRow = ContentValues().apply {
    // Specifies the MIME type for this data row (all data rows must be marked by their type)
    put(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)

    // Adds the phone number and its type to the row
    put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
}

// Adds the row to the array
contactData.add(phoneRow)

/*
 * Sets up the email data row
 */

// Sets up the row as a ContentValues object
val emailRow = ContentValues().apply {
    // Specifies the MIME type for this data row (all data rows must be marked by their type)
    put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)

    // Adds the email address and its type to the row
    put(ContactsContract.CommonDataKinds.Email.ADDRESS, email)
}

// Adds the row to the array
contactData.add(emailRow)

// Creates a new intent for sending to the device's contacts application
val insertIntent = Intent(ContactsContract.Intents.Insert.ACTION).apply {
    // Sets the MIME type to the one expected by the insertion activity
    type = ContactsContract.RawContacts.CONTENT_TYPE

    // Sets the new contact name
    putExtra(ContactsContract.Intents.Insert.NAME, name)

    // Sets the new company and job title
    putExtra(ContactsContract.Intents.Insert.COMPANY, company)
    putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle)

    /*
    * Adds the array to the intent's extras. It must be a parcelable object in order to
    * travel between processes. The device's contacts app expects its key to be
    * Intents.Insert.DATA
    */
    putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData)
}

// Send out the intent to start the device's contacts app in its add contact activity.
startActivity(insertIntent)

Java

// Gets values from the UI
String name = contactNameEditText.getText().toString();
String phone = contactPhoneEditText.getText().toString();
String email = contactEmailEditText.getText().toString();

String company = companyName.getText().toString();
String jobtitle = jobTitle.getText().toString();

// Creates a new intent for sending to the device's contacts application
Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION);

// Sets the MIME type to the one expected by the insertion activity
insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE);

// Sets the new contact name
insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name);

// Sets the new company and job title
insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company);
insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle);

/*
 * Demonstrates adding data rows as an array list associated with the DATA key
 */

// Defines an array list to contain the ContentValues objects for each row
ArrayList<ContentValues> contactData = new ArrayList<ContentValues>();


/*
 * Defines the raw contact row
 */

// Sets up the row as a ContentValues object
ContentValues rawContactRow = new ContentValues();

// Adds the account type and name to the row
rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.getType());
rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.getName());

// Adds the row to the array
contactData.add(rawContactRow);

/*
 * Sets up the phone number data row
 */

// Sets up the row as a ContentValues object
ContentValues phoneRow = new ContentValues();

// Specifies the MIME type for this data row (all data rows must be marked by their type)
phoneRow.put(
        ContactsContract.Data.MIMETYPE,
        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
);

// Adds the phone number and its type to the row
phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone);

// Adds the row to the array
contactData.add(phoneRow);

/*
 * Sets up the email data row
 */

// Sets up the row as a ContentValues object
ContentValues emailRow = new ContentValues();

// Specifies the MIME type for this data row (all data rows must be marked by their type)
emailRow.put(
        ContactsContract.Data.MIMETYPE,
        ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE
);

// Adds the email address and its type to the row
emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email);

// Adds the row to the array
contactData.add(emailRow);

/*
 * Adds the array to the intent's extras. It must be a parcelable object in order to
 * travel between processes. The device's contacts app expects its key to be
 * Intents.Insert.DATA
 */
insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData);

// Send out the intent to start the device's contacts app in its add contact activity.
startActivity(insertIntent);

תקינות נתונים

מאגר אנשי הקשר מכיל מידע חשוב ורגיש שהמשתמשים מצפים שיהיה נכון ועדכני, ולכן ל-Contacts Provider יש כללים מוגדרים היטב לשמירה על תקינות הנתונים. באחריותכם לפעול בהתאם לכללים האלה כשאתם משנים את נתוני אנשי הקשר. הדבר החשוב הכללים מפורטים כאן:

תמיד צריך להוסיף שורה של 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 מספקת מסגרת לסנכרון יישומי פלאגין שהופכת את המשימות הבאות לאוטומטיות:

  • בדיקת זמינות הרשת.
  • תזמון וביצוע סנכרון על סמך העדפות המשתמשים.
  • הפעלה מחדש של סנכרון שנעצר.

כדי להשתמש במסגרת הזו, אתם צריכים לספק פלאגין של מתאם סנכרון. כל מתאם סנכרון הוא ייחודי ספק שירות ותוכן, אבל יכול לטפל בכמה שמות של חשבונות עבור אותו שירות. framework מאפשרת גם כמה מתאמי סנכרון לאותו שירות ולאותו ספק.

סנכרון של סוגי מתאמים וקבצים

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

הערה: שימוש בסוג חשבון כחלק מהזיהוי של מתאם הסנכרון מאפשר למערכת לזהות ולקבץ יחד מתאמי סנכרון שיש להם גישה לשירותים שונים מאותו ארגון. לדוגמה, לכל מתאמי הסנכרון של שירותי Google אונליין יש את אותו סוג חשבון com.google. כשמשתמשים מוסיפים חשבון Google למכשירים שלהם, כל מתאמי הסנכרון המותקנים לשירותי Google מופיעים יחד ברשימה. כל מתאם סנכרון שמופיע ברשימה מסתנכרן עם ספק תוכן אחר במכשיר.

מאחר שרוב השירותים דורשים מהמשתמשים לאמת את הזהות שלהם לפני שהם יכולים לגשת לנתונים, מערכת Android מציעה מסגרת אימות שדומה למסגרת של מתאם הסנכרון, ולעיתים קרובות משתמשים בה בשילוב עם המסגרת הזו. מסגרת האימות משתמשת באימותי פלאגין שהם קבוצות משנה של AbstractAccountAuthenticator. מאמת חשבונות מאמת את זהות המשתמש לפי השלבים הבאים:

  1. אוסף את שם המשתמש, סיסמה או מידע דומה ( פרטי כניסה).
  2. שליחת פרטי הכניסה לשירות
  3. בדיקת התשובה של השירות.

אם השירות מקבל את פרטי הכניסה, מאמת החשבונות יכול לשמור אותם לשימוש מאוחר יותר. בגלל מסגרת האימות של הפלאגין, ה-AccountManager יכול לספק גישה לכל אסימון אימות שתומך בו האימות ובוחר לחשוף, כמו אסימוני אימות של OAuth2.

למרות שלא נדרש אימות, רוב שירותי אנשי הקשר משתמשים בו. עם זאת, אין צורך להשתמש במסגרת האימות של Android כדי לבצע אימות.

הטמעת מתאם סנכרון

כדי להטמיע מתאם סנכרון עבור ספק אנשי הקשר, צריך להתחיל ביצירת אפליקציית Android שמכילה את הפרטים הבאים:

רכיב Service שמגיב לבקשות מהמערכת כדי חיבור למתאם הסנכרון.
כשהמערכת רוצה להריץ סנכרון, היא קוראת ל-method‏ onBind() של השירות כדי לקבל IBinder למתאם הסנכרון. כך המערכת יכולה מבצעים קריאות שונות ב-methods של המתאם.
מתאם הסנכרון בפועל, שמיושם כסוג משנה קונקרטי של AbstractThreadedSyncAdapter.
הכיתה הזו מורידה נתונים מהשרת, ומעלה נתונים המכשיר ופתרון התנגשויות. העבודה העיקרית של המתאם היא מבצעים את הפעולה הזאת בשיטה onPerformSync(). המחלקה הזו חייבת להיות מופצת כ-Singleton.
מחלקה של Application.
הסיווג הזה משמש כמפעל עבור singleton של מתאם הסנכרון. משתמשים בשיטה onCreate() כדי ליצור מופע של מתאם הסנכרון, ומספקים שיטה סטטית מסוג 'getter' כדי להחזיר את ה-Singleton לשיטה onBind() של השירות של מתאם הסנכרון.
אופציונלי: רכיב Service שמגיב בקשות מהמערכת לאימות משתמשים.
AccountManager מפעיל את השירות הזה כדי להתחיל את האימות תהליך האימות. ה-method onCreate() של השירות יוצרת של מאמת החשבונות. כשהמערכת רוצה לאמת חשבון משתמש למתאמת הסנכרון של האפליקציה, היא קוראת לשיטה onBind() של השירות כדי לקבל IBinder לאימות. כך המערכת יכולה לבצע קריאות צולבות ל-methods של המאמת.
אופציונלי: תת-סוג קונקרטי של AbstractAccountAuthenticator שמטפל בבקשות לאימות.
בכיתה הזו מפורטות שיטות שמופעלות על ידי AccountManager כדי לאמת את פרטי הכניסה של המשתמש מול השרת. הפרטים של תהליכי האימות משתנים במידה רבה, בהתאם לטכנולוגיית השרת שבה משתמשים. אתם צריכים לקבלת מידע נוסף על אימות, אפשר לעיין בתיעוד של תוכנת השרת שלכם.
קובצי XML שמגדירים את מתאם הסנכרון ואת המאמת למערכת.
רכיבי השירות של מתאם הסנכרון ומאמת הזהות שתוארו למעלה מוגדרים ברכיבי <service> במניפסט של האפליקציה. הרכיבים האלה מכילים <meta-data> ורכיבי צאצא שמספקים נתונים ספציפיים למערכת:
  • <meta-data> עבור נקודות השירות של מתאם הסנכרון קובץ XML res/xml/syncadapter.xml. קובץ זה מציין URI של שירות האינטרנט שיתוזמן עם ספק אנשי הקשר, וגם סוג חשבון לשירות האינטרנט.
  • אופציונלי: הרכיב <meta-data> של המאמת מפנה לקובץ ה-XML res/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. השאילתה מחזירה סמן שמכיל שורה אחת, עם העמודה היחידה android.provider.ContactsContract.StreamItems#MAX_ITEMS.

הכיתה android.provider.ContactsContract.StreamItems.StreamItemPhotos מגדירה טבלת משנה של android.provider.ContactsContract.StreamItemPhotos שמכילה את שורות התמונות של פריט אחד במקור החדשות.

אינטראקציות עם שידור חי ברשתות חברתיות

נתוני הזרם ברשתות החברתיות שמנוהלים על ידי הספק 'אנשי קשר', בשילוב עם אפליקציית אנשי הקשר במכשיר, מציעה דרך עוצמתית לחבר את מערכת הרשת החברתית שלכם עם אנשי קשר קיימים. התכונות הבאות זמינות:

  • כשמסנכרנים את שירות הרשת החברתית עם ספק אנשי הקשר באמצעות מתאם סנכרון, אפשר לאחזר את הפעילות האחרונה של אנשי הקשר של המשתמש ולאחסן אותה בטבלאות android.provider.ContactsContract.StreamItems ו-android.provider.ContactsContract.StreamItemPhotos לשימוש עתידי.
  • בנוסף לסנכרון הרגיל, אפשר להפעיל את מתאם הסנכרון כדי לאחזר נתונים נוספים כשהמשתמש בוחר איש קשר להצגה. כך מתאם הסנכרון יוכל לאחזר תמונות ברזולוציה גבוהה ואת הפריטים האחרונים שפורסמו בסטורי של איש הקשר.
  • על ידי רישום התראה באפליקציית אנשי הקשר של המכשיר ובאפליקציית 'אנשי קשר' ספק, יש לך אפשרות לקבל כוונה לצפות באיש קשר מסוים ובאותו זמן לעדכן את הסטטוס של איש הקשר מהשירות. הגישה הזו עשויה להיות מהירה יותר ולצרוך פחות רוחב פס מאשר סנכרון מלא באמצעות מתאם סנכרון.
  • המשתמשים יכולים להוסיף איש קשר לשירות הרשת החברתית שלכם כשהם צופים באיש הקשר באפליקציית אנשי הקשר של המכשיר. אפשר להפעיל את האפשרות הזו באמצעות 'הזמנת איש קשר' פיצ'ר, שאתה מפעיל באמצעות שילוב של פעילות שמוסיפה איש קשר קיים רשת, וקובץ XML שמספק את אפליקציית אנשי הקשר של המכשיר ספק אנשי הקשר עם פרטי האפליקציה שלכם.

סנכרון קבוע של פריטי הסטרימינג עם ספק אנשי הקשר זהה לסנכרון עם ספקים אחרים. מידע נוסף על סנכרון זמין בקטע מתאמי סנכרון של ספקי אנשי קשר. בקטעים הבאים מוסבר איך לרשום התראות ולהזמין אנשי קשר.

רישום לטיפול בבקשות לצפיות ברשתות חברתיות

כדי לרשום את מתאם הסנכרון לקבלת התראות כשמשתמש צופה באיש קשר מנוהל על ידי מתאם הסנכרון:

  1. יצירת קובץ בשם contacts.xml ב-res/xml/ של הפרויקט אם הקובץ הזה כבר נמצא ברשותך, אפשר לדלג על השלב הזה.
  2. לקובץ הזה, מוסיפים את הרכיב <ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"> אם הרכיב הזה כבר קיים, אפשר לדלג על השלב הזה.
  3. כדי לרשום שירות שמקבל התראה כשהמשתמש פותח דף פרטים של איש קשר את אפליקציית אנשי הקשר של המכשיר, צריך להוסיף את המאפיין viewContactNotifyService="serviceclass" לרכיב, כאשר serviceclass הוא שם הסיווג המוגדר במלואו של השירות שאמור לקבל את הכוונה מאפליקציית אנשי הקשר של המכשיר. עבור שירות ההתראות השירות, משתמשים במחלקה שמרחיבה את IntentService כדי לאפשר לשירות לקבל כוונות. הנתונים בהפניה הנכנסת מכילים את ה-URI של התוכן של נתוני ה-Intent הגולמיים איש הקשר שעליו המשתמש לחץ. משירות שירות ההתראות, ניתן לבצע קישור אל ואז להתקשר אל לסנכרון הנתונים של איש הקשר הגולמי.

כדי לרשום פעילות שתתבצע קריאה כשמשתמש לוחץ על פריט בשידור, על תמונה או על שניהם:

  1. יצירת קובץ בשם contacts.xml ב-res/xml/ של הפרויקט אם הקובץ כבר קיים, אפשר לדלג על השלב הזה.
  2. בקובץ הזה, מוסיפים את הרכיב <ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">. אם הרכיב הזה כבר קיים, אפשר לדלג על השלב הזה.
  3. כדי לרשום אחת מהפעילויות שלכם לטפל במקרה שבו המשתמש לוחץ על פריט בסטרימינג באפליקציית אנשי הקשר של המכשיר, מוסיפים את המאפיין viewStreamItemActivity="activityclass" לאלמנט, כאשר activityclass הוא שם הכיתה המלא של הפעילות שאמורה לקבל את הכוונה מאפליקציית אנשי הקשר של המכשיר.
  4. כדי לרשום אחת מהפעילויות שלכם לטפל במקרה שבו המשתמש לוחץ על תמונה בסטרים באפליקציית אנשי הקשר של המכשיר, מוסיפים את המאפיין viewStreamItemPhotoActivity="activityclass" לאלמנט, כאשר activityclass הוא שם הכיתה המלא של הפעילות שאמורה לקבל את ה-Intent מאפליקציית אנשי הקשר של המכשיר.

תיאור מפורט יותר של הרכיב <ContactsAccountType> זמין בקטע הרכיב <ContactsAccountType>.

ה-Intent הנכנס מכיל את ה-URI של התוכן של הפריט או התמונה שהמשתמש לחץ עליהם. כדי ליצור פעילויות נפרדות לפריטי טקסט ולתמונות, צריך להשתמש בשני המאפיינים באותו קובץ.

אינטראקציה עם שירות הרשת החברתית שלכם

המשתמשים לא צריכים לצאת מאפליקציית אנשי הקשר של המכשיר כדי להזמין איש קשר לרשת החברתית. לאחר יצירת רישות. במקום זאת, אפשר להגדיר שאפליקציית אנשי הקשר במכשיר תשלח כוונה להזמנת איש הקשר לאחת מהפעילויות שלכם. כדי להגדיר זאת:

  1. יצירת קובץ בשם contacts.xml ב-res/xml/ של הפרויקט אם כבר יש לכם את הקובץ הזה, אתם יכולים לדלג על השלב הזה.
  2. לקובץ הזה, מוסיפים את הרכיב <ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"> אם הרכיב הזה כבר קיים, אפשר לדלג על השלב הזה.
  3. מוסיפים את המאפיינים הבאים:
    • inviteContactActivity="activityclass"
    • inviteContactActionLabel="@string/invite_action_label"
    הערך של activityclass הוא שם המחלקה המלא של הפעילות שאמורה לקבל את ה-Intent. 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
מכשיר Android משאב שניתן לשרטוט שאפליקציית 'אנשי קשר' מציגה לצד הנתונים שלכם. אפשר להשתמש בו כדי להצביע למשתמש שהנתונים מגיעים מהשירות שלכם.
android:summaryColumn
שם העמודה של הערך הראשון מתוך שני שאוחזר משורת הנתונים. מוצג בתור השורה הראשונה ברשומה עבור שורת הנתונים הזו. השורה הראשונה היא שמיועד לשמש כסיכום של הנתונים, אבל זה אופציונלי. אפשר לעיין גם במאמר android:detailColumn.
android:detailColumn
שם העמודה של הערך השני מתוך שני ערכים שאוחזרו משורת הנתונים. הערך הוא מוצגת כשורה השנייה של הרשומה עבור שורת הנתונים הזו. עוד באותו הקשר android:summaryColumn

תכונות נוספות של ספק אנשי הקשר

בנוסף לתכונות הראשיות המתוארות בקטעים הקודמים, ספק אנשי הקשר מציע את התכונות השימושיות הבאות לעבודה עם נתוני אנשי הקשר:

  • קבוצות של אנשי קשר
  • תכונות שקשורות לתמונות

קבוצות של אנשי קשר

ספק אנשי הקשר יכול באופן אופציונלי להוסיף תוויות לאוספים של אנשי קשר קשורים עם לקבץ נתונים. אם השרת משויך לחשבון משתמש אם רוצים לתחזק קבוצות, מתאם הסנכרון של סוג החשבון אמור להעביר מקבץ נתונים בין ספק אנשי הקשר לשרת. כשמשתמשים מוסיפים איש קשר חדש לשרת ואז מוסיפים אותו לקבוצה חדשה, מתאם הסנכרון צריך להוסיף את הקבוצה החדשה לטבלה ContactsContract.Groups. הקבוצה או מקבצת קובץ RAW אנשי הקשר ששייכים ל- מאוחסנים בטבלה 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, מתוארת במידע נוסף מפורט בקטע תמונות של רשתות חברתיות.