ผู้ให้บริการรายชื่อติดต่อเป็นคอมโพเนนต์ Android ที่มีประสิทธิภาพและยืดหยุ่นซึ่งจัดการที่เก็บข้อมูลส่วนกลางของอุปกรณ์เกี่ยวกับผู้คน ผู้ให้บริการรายชื่อติดต่อคือแหล่งข้อมูล ที่คุณเห็นในแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ และคุณยังเข้าถึงข้อมูลใน แอปพลิเคชันของคุณเองและโอนข้อมูลระหว่างอุปกรณ์กับบริการออนไลน์ได้ด้วย ผู้ให้บริการรองรับ แหล่งข้อมูลที่หลากหลายและพยายามจัดการข้อมูลให้ได้มากที่สุดสำหรับแต่ละบุคคล ซึ่งส่งผลให้องค์กรมีความซับซ้อน ด้วยเหตุนี้ API ของผู้ให้บริการจึงมีชุดคลาสและอินเทอร์เฟซของสัญญาที่ครอบคลุม ซึ่งช่วยให้ทั้งการดึงข้อมูลและการแก้ไขข้อมูลเป็นไปได้
คู่มือนี้อธิบายสิ่งต่อไปนี้
- โครงสร้างพื้นฐานของผู้ให้บริการ
- วิธีกู้คืนข้อมูลจากผู้ให้บริการ
- วิธีแก้ไขข้อมูลในผู้ให้บริการ
- วิธีเขียน Sync Adapter สำหรับซิงค์ข้อมูลจากเซิร์ฟเวอร์ไปยัง ผู้ให้บริการรายชื่อติดต่อ
คู่มือนี้ถือว่าคุณทราบข้อมูลพื้นฐานเกี่ยวกับผู้ให้บริการเนื้อหาของ Android ดูข้อมูลเพิ่มเติม เกี่ยวกับผู้ให้บริการเนื้อหาของ Android ได้ที่คู่มือ พื้นฐานของผู้ให้บริการเนื้อหา
องค์กร Contacts Provider
Contacts Provider เป็นคอมโพเนนต์ผู้ให้บริการเนื้อหาของ Android โดยจะเก็บข้อมูล 3 ประเภทเกี่ยวกับบุคคล ซึ่งแต่ละประเภทจะสอดคล้องกับตารางที่ผู้ให้บริการเสนอ ดังที่แสดงในรูปที่ 1
 
รูปที่ 1 โครงสร้างตาราง Contacts Provider
โดยทั่วไปแล้วตารางทั้ง 3 ตารางนี้จะอ้างอิงตามชื่อของคลาสสัญญา คลาส กำหนดค่าคงที่สำหรับ URI ของเนื้อหา ชื่อคอลัมน์ และค่าคอลัมน์ที่ใช้โดยตารางต่อไปนี้
- 
        ContactsContract.Contactsตาราง
- แถวที่แสดงบุคคลต่างๆ โดยอิงตามการรวบรวมแถวรายชื่อติดต่อดิบ
- 
        ContactsContract.RawContactsตาราง
- แถวที่มีข้อมูลสรุปของบุคคลหนึ่งๆ ซึ่งเฉพาะเจาะจงสำหรับบัญชีผู้ใช้และประเภท
- 
        ContactsContract.Dataตาราง
- แถวที่มีรายละเอียดสำหรับรายชื่อติดต่อดิบ เช่น อีเมลหรือหมายเลขโทรศัพท์
    ตารางอื่นๆ ที่แสดงโดยคลาสสัญญาใน ContactsContract
    คือตารางเสริมที่ผู้ให้บริการรายชื่อติดต่อใช้เพื่อจัดการการดำเนินการหรือรองรับ
    ฟังก์ชันเฉพาะในแอปพลิเคชันรายชื่อติดต่อหรือโทรศัพท์ของอุปกรณ์
ข้อมูลติดต่อดิบ
รายชื่อติดต่อดิบแสดงข้อมูลของบุคคลที่มาจากบัญชีประเภทเดียวและชื่อบัญชี เนื่องจากผู้ให้บริการรายชื่อติดต่ออนุญาตให้ใช้บริการออนไลน์มากกว่า 1 รายการเป็นแหล่งข้อมูลของบุคคลหนึ่งๆ ผู้ให้บริการรายชื่อติดต่อจึงอนุญาตให้ใช้รายชื่อติดต่อดิบหลายรายการสำหรับบุคคลเดียวกัน นอกจากนี้ รายชื่อติดต่อดิบหลายรายการยังช่วยให้ผู้ใช้รวมข้อมูลของบุคคลจากบัญชีมากกว่า 1 บัญชี จากบัญชีประเภทเดียวกันได้ด้วย
    ระบบจะไม่จัดเก็บข้อมูลส่วนใหญ่ของรายชื่อติดต่อดิบในตาราง ContactsContract.RawContacts แต่จะจัดเก็บไว้ในแถวอย่างน้อย 1 แถวในตาราง 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ระบุประเภทบัญชีของคุณเสมอ
            ด้วยตัวระบุโดเมนสำหรับโดเมนที่คุณเป็นเจ้าของหรือควบคุม ซึ่งจะช่วยให้มั่นใจได้ว่าประเภทบัญชีของคุณจะไม่ซ้ำกับใคร | บัญชีประเภทที่มีข้อมูลรายชื่อติดต่อมักจะมี Sync Adapter ที่เชื่อมโยงกันซึ่งจะ ซิงค์กับผู้ให้บริการรายชื่อติดต่อ | 
| DELETED | แฟล็ก "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) ก่อนแอปจะเพิ่มแถวรายชื่อติดต่อดิบได้ คุณสามารถอธิบายข้อกำหนดนี้แก่ผู้ใช้ในเอกสารประกอบ หรือแจ้งให้ผู้ใช้เพิ่มประเภทและชื่อ หรือทั้ง 2 อย่าง ประเภทบัญชีและชื่อบัญชี มีการอธิบายอย่างละเอียดในส่วนถัดไป
แหล่งที่มาของข้อมูลรายชื่อติดต่อดิบ
หากต้องการทำความเข้าใจวิธีการทำงานของรายชื่อติดต่อดิบ ให้พิจารณาผู้ใช้ "Emily Dickinson" ซึ่งมีบัญชีผู้ใช้ 3 บัญชีต่อไปนี้ในอุปกรณ์
- emily.dickinson@gmail.com
- emilyd@gmail.com
- บัญชี Twitter "belle_of_amherst"
ผู้ใช้รายนี้ได้เปิดใช้ซิงค์รายชื่อติดต่อสำหรับบัญชีทั้ง 3 บัญชีนี้ในการตั้งค่าบัญชี
    สมมติว่าเอมิลี ดิกคินสันเปิดหน้าต่างเบราว์เซอร์ ลงชื่อเข้าใช้ Gmail ในชื่อ
    emily.dickinson@gmail.com เปิด
    รายชื่อติดต่อ และเพิ่ม "Thomas Higginson" ต่อมาเธอเข้าสู่ระบบ Gmail ในชื่อ
    emilyd@gmail.com และส่งอีเมลถึง "Thomas Higginson" ซึ่งระบบจะเพิ่ม
    เขาเป็นรายชื่อติดต่อโดยอัตโนมัติ นอกจากนี้ เธอยังติดตาม "colonel_tom" (รหัส Twitter ของ Thomas Higginson) บน
    Twitter ด้วย
Contacts Provider จะสร้างรายชื่อติดต่อดิบ 3 รายการอันเป็นผลมาจากการดำเนินการนี้
- 
        ข้อมูลติดต่อดิบสำหรับ "Thomas Higginson" ที่เชื่อมโยงกับ emily.dickinson@gmail.comประเภทบัญชีผู้ใช้คือ Google
- 
        ข้อมูลติดต่อดิบที่ 2 สำหรับ "Thomas Higginson" ที่เชื่อมโยงกับ emilyd@gmail.comประเภทบัญชีผู้ใช้คือ Google มีรายชื่อติดต่อดิบรายการที่ 2 แม้ว่าชื่อจะเหมือนกับชื่อก่อนหน้าก็ตาม เนื่องจากมีการเพิ่มบุคคลดังกล่าวสำหรับบัญชีผู้ใช้ที่แตกต่างกัน
- รายชื่อติดต่อดิบที่ 3 สำหรับ "Thomas Higginson" ที่เชื่อมโยงกับ "belle_of_amherst" ประเภทบัญชีผู้ใช้คือ Twitter
ข้อมูล
    ดังที่ได้กล่าวไว้ก่อนหน้านี้ ข้อมูลสำหรับรายชื่อติดต่อดิบจะจัดเก็บไว้ในแถว ContactsContract.Data ที่ลิงก์กับค่า _ID ของรายชื่อติดต่อดิบ ซึ่งช่วยให้ผู้ติดต่อแบบดิบรายเดียวมีข้อมูลประเภทเดียวกันได้หลายอินสแตนซ์ เช่น อีเมลหรือหมายเลขโทรศัพท์ ตัวอย่างเช่น หาก
    "Thomas Higginson" สำหรับ emilyd@gmail.com  (แถวรายชื่อติดต่อดิบสำหรับ Thomas Higginson
    ที่เชื่อมโยงกับบัญชี Google emilyd@gmail.com) มีอีเมลส่วนตัวเป็น
    thigg@gmail.com และอีเมลที่ทำงานเป็น
    thomas.higginson@gmail.com ผู้ให้บริการรายชื่อติดต่อจะจัดเก็บแถวอีเมล 2 รายการ
    และลิงก์ทั้ง 2 รายการกับรายชื่อติดต่อดิบ
    โปรดทราบว่าระบบจะจัดเก็บข้อมูลประเภทต่างๆ ไว้ในตารางเดียวนี้ แถวชื่อที่แสดง
    หมายเลขโทรศัพท์ อีเมล ที่อยู่ทางไปรษณีย์ รูปภาพ และรายละเอียดเว็บไซต์ทั้งหมดจะอยู่ในตาราง
    ContactsContract.Data ตาราง
    ContactsContract.Data มีคอลัมน์บางรายการที่มีชื่อสื่อความหมาย
    และคอลัมน์อื่นๆ ที่มีชื่อทั่วไป เพื่อช่วยในการจัดการ เนื้อหาของคอลัมน์ชื่อที่สื่อความหมายจะมี
    ความหมายเดียวกันไม่ว่าจะเป็นข้อมูลประเภทใดในแถว ส่วนเนื้อหาของคอลัมน์ชื่อทั่วไปจะมี
    ความหมายแตกต่างกันไปตามประเภทของข้อมูล
ชื่อคอลัมน์ที่สื่อความหมาย
ตัวอย่างชื่อคอลัมน์ที่สื่อความหมายมีดังนี้
- 
        RAW_CONTACT_ID
- 
        ค่าของคอลัมน์ _IDของรายชื่อติดต่อดิบสำหรับข้อมูลนี้
- 
        MIMETYPE
- 
        ประเภทของข้อมูลที่จัดเก็บในแถวนี้ ซึ่งแสดงเป็นประเภท MIME ที่กำหนดเอง Contacts Provider
        ใช้ประเภท MIME ที่กำหนดไว้ในคลาสย่อยของ
        ContactsContract.CommonDataKindsMIME ประเภทเหล่านี้เป็นโอเพนซอร์ส และแอปพลิเคชันหรืออะแดปเตอร์การซิงค์ใดก็ได้ที่ใช้ได้กับผู้ให้บริการรายชื่อติดต่อจะใช้ MIME ประเภทเหล่านี้ได้
- 
        IS_PRIMARY
- 
        หากแถวข้อมูลประเภทนี้เกิดขึ้นได้มากกว่า 1 ครั้งสำหรับรายชื่อติดต่อดิบ คอลัมน์ IS_PRIMARYจะติด แฟล็กแถวข้อมูลที่มีข้อมูลหลักสำหรับประเภทนั้น เช่น หาก ผู้ใช้กดหมายเลขโทรศัพท์ของรายชื่อติดต่อค้างไว้แล้วเลือกตั้งค่าเริ่มต้น แถวContactsContract.Dataที่มีหมายเลขนั้น จะมีคอลัมน์IS_PRIMARYตั้งค่าเป็น ค่าที่ไม่ใช่ 0
ชื่อคอลัมน์ทั่วไป
    มีคอลัมน์ทั่วไป 15 รายการชื่อ DATA1 ถึง
    DATA15 ซึ่งพร้อมให้บริการโดยทั่วไป และคอลัมน์ทั่วไปอีก 4 รายการ
    ชื่อ 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 แถว และวิธีที่ชื่อคอลัมน์เฉพาะประเภท "ซ้อนทับ"
    ชื่อคอลัมน์ทั่วไป
 
รูปที่ 2 ชื่อคอลัมน์เฉพาะประเภทและชื่อคอลัมน์ทั่วไป
คลาสชื่อคอลัมน์เฉพาะประเภท
ตารางที่ 2 แสดงรายการคลาสชื่อคอลัมน์เฉพาะประเภทที่ใช้กันมากที่สุด
ตารางที่ 2 คลาสชื่อคอลัมน์เฉพาะประเภท
| ชั้นเรียนการแมป | ประเภทของข้อมูล | หมายเหตุ | 
|---|---|---|
| ContactsContract.CommonDataKinds.StructuredName | ข้อมูลชื่อสำหรับรายชื่อติดต่อดิบที่เชื่อมโยงกับแถวข้อมูลนี้ | รายชื่อติดต่อดิบจะมีแถวเหล่านี้เพียงแถวเดียว | 
| ContactsContract.CommonDataKinds.Photo | รูปภาพหลักสำหรับรายชื่อติดต่อดิบที่เชื่อมโยงกับแถวข้อมูลนี้ | รายชื่อติดต่อดิบจะมีแถวเหล่านี้เพียงแถวเดียว | 
| ContactsContract.CommonDataKinds.Email | อีเมลสำหรับผู้ติดต่อดิบที่เชื่อมโยงกับแถวข้อมูลนี้ | รายชื่อติดต่อดิบมีอีเมลได้หลายรายการ | 
| ContactsContract.CommonDataKinds.StructuredPostal | ที่อยู่ไปรษณีย์ของผู้ติดต่อดิบที่เชื่อมโยงกับแถวข้อมูลนี้ | รายชื่อติดต่อดิบมีที่อยู่ไปรษณีย์ได้หลายรายการ | 
| ContactsContract.CommonDataKinds.GroupMembership | ตัวระบุที่ลิงก์รายชื่อติดต่อดิบกับกลุ่มใดกลุ่มหนึ่งในผู้ให้บริการรายชื่อติดต่อ | กลุ่มเป็นฟีเจอร์ที่ไม่บังคับของประเภทบัญชีและชื่อบัญชี ซึ่งจะอธิบายอย่างละเอียดในส่วนกลุ่มรายชื่อติดต่อ | 
รายชื่อติดต่อ
Contacts Provider จะรวมแถวข้อมูลติดต่อดิบในบัญชีทุกประเภทและชื่อบัญชี เพื่อสร้างรายชื่อติดต่อ ซึ่งช่วยให้แสดงและแก้ไขข้อมูลทั้งหมดที่ผู้ใช้รวบรวมไว้สำหรับบุคคลหนึ่งๆ ได้ง่ายขึ้น ผู้ให้บริการรายชื่อติดต่อจะจัดการการสร้างแถวรายชื่อติดต่อใหม่ และการรวบรวมรายชื่อติดต่อดิบกับแถวรายชื่อติดต่อที่มีอยู่ ทั้งแอปพลิเคชันและ ตัวปรับการซิงค์ไม่ได้รับอนุญาตให้เพิ่มรายชื่อติดต่อ และคอลัมน์บางคอลัมน์ในแถวรายชื่อติดต่อเป็นแบบอ่านอย่างเดียว
    หมายเหตุ: หากพยายามเพิ่มรายชื่อติดต่อลงในผู้ให้บริการรายชื่อติดต่อด้วย
    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 ตาราง
 
รูปที่ 3 ความสัมพันธ์ของตารางรายชื่อติดต่อ รายชื่อติดต่อดิบ และรายละเอียด
ข้อควรระวัง: หากคุณเผยแพร่แอปไปยัง Google Play Store หรือหากแอปของคุณ อยู่ในอุปกรณ์ที่ใช้ 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 เหล่านี้ ให้ใช้วิธีอื่น ตัวอย่างเช่น คุณสามารถตอบสนอง Use Case บางอย่างได้โดยใช้ ผู้ให้บริการเนื้อหาส่วนตัวหรือข้อมูลอื่นๆ ที่จัดเก็บไว้ในแอปหรือระบบแบ็กเอนด์ ของคุณ
หากต้องการยืนยันว่าฟังก์ชันการทำงานของแอปไม่ได้รับผลกระทบจากการเปลี่ยนแปลงนี้ คุณ สามารถล้างช่องข้อมูลเหล่านี้ด้วยตนเองได้ โดยให้เรียกใช้คำสั่ง ADB ต่อไปนี้ในอุปกรณ์ที่ใช้ Android 4.1 (API ระดับ 16) ขึ้นไป
adb shell content delete \ --uri content://com.android.contacts/contacts/delete_usage
ข้อมูลจากอะแดปเตอร์การซิงค์
    ผู้ใช้จะป้อนข้อมูลรายชื่อติดต่อลงในอุปกรณ์โดยตรง แต่ข้อมูลจะไหลเข้าสู่ Contacts
    Provider จากบริการบนเว็บผ่านตัวปรับการซิงค์ ซึ่งจะทำให้การโอนข้อมูลระหว่างอุปกรณ์กับบริการเป็นไปโดยอัตโนมัติ
 Sync Adapters ทำงานในเบื้องหลัง
    ภายใต้การควบคุมของระบบ และเรียกใช้ContentResolverเมธอด
    เพื่อจัดการข้อมูล
ใน Android บริการเว็บที่ Sync Adapter ทำงานด้วยจะระบุโดยประเภทบัญชี Sync Adapter แต่ละตัวจะทำงานกับบัญชีประเภทเดียว แต่รองรับชื่อบัญชีหลายชื่อสำหรับประเภทนั้นได้ ประเภทบัญชีและชื่อบัญชีอธิบายไว้สั้นๆ ในส่วน แหล่งที่มาของข้อมูลรายชื่อติดต่อดิบ คำจำกัดความต่อไปนี้จะให้รายละเอียดเพิ่มเติม และอธิบายว่าประเภทและชื่อบัญชีเกี่ยวข้องกับตัวดัดแปลงและบริการการซิงค์อย่างไร
- ประเภทบัญชี
- 
        ระบุบริการที่ผู้ใช้จัดเก็บข้อมูลไว้ โดยส่วนใหญ่แล้ว ผู้ใช้จะต้อง
        ตรวจสอบสิทธิ์กับบริการ เช่น Google Contacts เป็นประเภทบัญชีที่ระบุด้วยรหัส google.comค่านี้สอดคล้องกับประเภทบัญชีที่ใช้โดยAccountManager
- ชื่อบัญชี
- ระบุบัญชีหรือการเข้าสู่ระบบสำหรับประเภทบัญชีที่เฉพาะเจาะจง บัญชี Google Contacts เหมือนกับบัญชี Google ซึ่งมีอีเมลเป็นชื่อบัญชี บริการอื่นๆ อาจใช้ชื่อผู้ใช้แบบคำเดียวหรือรหัสตัวเลข
ประเภทบัญชีไม่จำเป็นต้องไม่ซ้ำกัน ผู้ใช้สามารถกำหนดค่าบัญชี Google Contacts หลายบัญชี และดาวน์โหลดข้อมูลไปยังผู้ให้บริการ Contacts ได้ ซึ่งอาจเกิดขึ้นหากผู้ใช้มีรายชื่อติดต่อส่วนตัวชุดหนึ่ง สำหรับชื่อบัญชีส่วนตัว และอีกชุดหนึ่งสำหรับงาน ชื่อบัญชีมักจะไม่ซ้ำกัน โดยทั้ง 2 อย่างนี้จะระบุการไหลของข้อมูลที่เฉพาะเจาะจงระหว่างผู้ให้บริการรายชื่อติดต่อกับ บริการภายนอก
หากต้องการโอนข้อมูลของบริการไปยังผู้ให้บริการรายชื่อติดต่อ คุณต้องเขียน Sync Adapter ของคุณเอง ซึ่งอธิบายไว้อย่างละเอียดในส่วนอะแดปเตอร์การซิงค์ของผู้ให้บริการรายชื่อติดต่อ
รูปที่ 4 แสดงให้เห็นว่าผู้ให้บริการรายชื่อติดต่ออยู่ในขั้นตอนการไหลของข้อมูล เกี่ยวกับผู้คนอย่างไร ในช่องที่ทำเครื่องหมายว่า "อะแดปเตอร์การซิงค์" อะแดปเตอร์แต่ละตัวจะมีป้ายกำกับตามประเภทบัญชี
 
รูปที่ 4 โฟลว์ข้อมูลของ Contacts Provider
สิทธิ์ที่จำเป็น
แอปพลิเคชันที่ต้องการเข้าถึงผู้ให้บริการรายชื่อติดต่อต้องขอสิทธิ์ต่อไปนี้
- สิทธิ์การอ่านตารางอย่างน้อย 1 รายการ
- 
        READ_CONTACTSที่ระบุในAndroidManifest.xmlด้วยองค์ประกอบ<uses-permission>เป็น<uses-permission android:name="android.permission.READ_CONTACTS">
- สิทธิ์การเขียนสำหรับตารางอย่างน้อย 1 รายการ
- 
        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" หากรายชื่อติดต่อเป็นโปรไฟล์ผู้ใช้
ข้อมูลเมตาของผู้ให้บริการรายชื่อติดต่อ
    Contacts Provider จัดการข้อมูลที่ติดตามสถานะของข้อมูลรายชื่อติดต่อใน
    ที่เก็บ ระบบจะจัดเก็บข้อมูลเมตานี้เกี่ยวกับที่เก็บไว้ในที่ต่างๆ ซึ่งรวมถึงแถวของตาราง
    Raw Contacts, Data และ Contacts, ตาราง
    ContactsContract.Settings และตาราง
    ContactsContract.SyncState ตารางต่อไปนี้แสดงผลของข้อมูลเมตาแต่ละรายการ
ตารางที่ 3 ข้อมูลเมตาใน Contacts Provider
| ตาราง | คอลัมน์ | ค่า | ความหมาย | 
|---|---|---|---|
| ContactsContract.RawContacts | DIRTY | "0" - ไม่มีการเปลี่ยนแปลงนับตั้งแต่ซิงค์ครั้งล่าสุด | ทำเครื่องหมายรายชื่อติดต่อดิบที่มีการเปลี่ยนแปลงในอุปกรณ์และต้องซิงค์กลับไปยังเซิร์ฟเวอร์ ผู้ให้บริการรายชื่อติดต่อจะตั้งค่าโดยอัตโนมัติเมื่อแอปพลิเคชัน Android
            อัปเดตแถว 
                Sync Adapter ที่แก้ไขตารางข้อมูลหรือรายชื่อติดต่อดิบควรต่อท้ายสตริง  | 
| "1" - มีการเปลี่ยนแปลงตั้งแต่การซิงค์ครั้งล่าสุด ต้องซิงค์กลับไปยังเซิร์ฟเวอร์ | |||
| ContactsContract.RawContacts | VERSION | หมายเลขเวอร์ชันของแถวนี้ | ผู้ให้บริการรายชื่อติดต่อจะเพิ่มค่านี้โดยอัตโนมัติเมื่อใดก็ตามที่แถวหรือ ข้อมูลที่เกี่ยวข้องมีการเปลี่ยนแปลง | 
| ContactsContract.Data | DATA_VERSION | หมายเลขเวอร์ชันของแถวนี้ | ผู้ให้บริการรายชื่อติดต่อจะเพิ่มค่านี้โดยอัตโนมัติทุกครั้งที่มีการเปลี่ยนแปลงแถวข้อมูล | 
| ContactsContract.RawContacts | SOURCE_ID | ค่าสตริงที่ระบุรายชื่อติดต่อดิบนี้ในบัญชีที่สร้างขึ้นอย่างไม่ซ้ำกัน | เมื่อตัวปรับการซิงค์สร้างรายชื่อติดต่อดิบใหม่ คอลัมน์นี้ควรตั้งค่าเป็นรหัสที่ไม่ซ้ำกันของเซิร์ฟเวอร์สำหรับรายชื่อติดต่อดิบ เมื่อแอปพลิเคชัน Android สร้าง
            รายชื่อติดต่อดิบใหม่ แอปพลิเคชันควรปล่อยให้คอลัมน์นี้ว่างไว้ ซึ่งจะส่งสัญญาณไปยังอะแดปเตอร์การซิงค์
            ว่าควรสร้างรายชื่อติดต่อดิบใหม่ในเซิร์ฟเวอร์ และรับค่าสำหรับ SOURCE_IDโดยเฉพาะอย่างยิ่ง รหัสแหล่งที่มาต้องไม่ซ้ำกันสำหรับบัญชีแต่ละประเภท และควรคงที่ตลอดการซิงค์ 
 | 
| ContactsContract.Groups | GROUP_VISIBLE | "0" - รายชื่อติดต่อในกลุ่มนี้ไม่ควรปรากฏใน UI ของแอปพลิเคชัน Android | คอลัมน์นี้ใช้เพื่อความเข้ากันได้กับเซิร์ฟเวอร์ที่อนุญาตให้ผู้ใช้ซ่อนรายชื่อติดต่อใน บางกลุ่ม | 
| "1" - อนุญาตให้รายชื่อติดต่อในกลุ่มนี้ปรากฏใน UI ของแอปพลิเคชัน | |||
| ContactsContract.Settings | UNGROUPED_VISIBLE | "0" - สำหรับบัญชีและประเภทบัญชีนี้ รายชื่อติดต่อที่ไม่ได้อยู่ในกลุ่มจะ ไม่ปรากฏใน UI ของแอปพลิเคชัน Android | โดยค่าเริ่มต้น รายชื่อติดต่อจะมองไม่เห็นหากไม่มีรายชื่อติดต่อดิบอยู่ในกลุ่ม
            (การเป็นสมาชิกกลุ่มสำหรับรายชื่อติดต่อดิบจะระบุด้วยแถวอย่างน้อย 1 แถว ContactsContract.CommonDataKinds.GroupMembershipในตารางContactsContract.Data)
            การตั้งค่าสถานะนี้ในContactsContract.Settingsแถวตาราง
            สำหรับประเภทบัญชีและบัญชีจะทำให้รายชื่อติดต่อที่ไม่มีกลุ่มแสดงได้
            การใช้แฟล็กนี้อย่างหนึ่งคือการแสดงรายชื่อติดต่อจากเซิร์ฟเวอร์ที่ไม่ได้ใช้กลุ่ม | 
| "1" - สำหรับบัญชีและประเภทบัญชีนี้ รายชื่อติดต่อที่ไม่ได้อยู่ในกลุ่มจะ มองเห็นได้ใน UI ของแอปพลิเคชัน | |||
| ContactsContract.SyncState | (ทั้งหมด) | ใช้ตารางนี้เพื่อจัดเก็บข้อมูลเมตาสำหรับตัวปรับการซิงค์ | ตารางนี้ช่วยให้คุณจัดเก็บสถานะการซิงค์และข้อมูลอื่นๆ ที่เกี่ยวข้องกับการซิงค์อย่างถาวรในอุปกรณ์ได้ | 
การเข้าถึง Contacts Provider
ส่วนนี้จะอธิบายหลักเกณฑ์ในการเข้าถึงข้อมูลจากผู้ให้บริการรายชื่อติดต่อ โดยเน้นที่ หัวข้อต่อไปนี้
- คำค้นหาเอนทิตี
- การแก้ไขเป็นกลุ่ม
- การดึงข้อมูลและการแก้ไขด้วย Intent
- ความสมบูรณ์ของข้อมูล
การแก้ไขจาก Sync Adapter จะอธิบายรายละเอียดเพิ่มเติมในส่วน Sync Adapter ของ Contacts Provider
การค้นหาเอนทิตี
    เนื่องจากตารางของ Contacts Provider จัดระเบียบเป็นลำดับชั้น จึงมักมีประโยชน์ที่จะ
    เรียกข้อมูลแถวและแถว "ย่อย" ทั้งหมดที่ลิงก์กับแถวนั้น เช่น หากต้องการแสดง
    ข้อมูลทั้งหมดของบุคคล คุณอาจต้องดึงข้อมูลContactsContract.RawContactsแถวทั้งหมดสำหรับContactsContract.Contactsแถวเดียว หรือContactsContract.CommonDataKinds.Emailแถวทั้งหมดสำหรับContactsContract.RawContactsแถวเดียว เพื่ออำนวยความสะดวกในเรื่องนี้ ผู้ให้บริการรายชื่อติดต่อ
    จึงมีโครงสร้างเอนทิตี ซึ่งทำหน้าที่เหมือนการรวมฐานข้อมูลระหว่าง
    ตาราง
    เอนทิตีก็เหมือนตารางที่ประกอบด้วยคอลัมน์ที่เลือกจากตารางหลักและตารางย่อย
    เมื่อค้นหาเอนทิตี คุณจะระบุการฉายภาพและเกณฑ์การค้นหาตามคอลัมน์
    ที่ใช้ได้จากเอนทิตี ผลลัพธ์คือ Cursor ที่มี
    แถว 1 แถวสำหรับแถวของตารางย่อยแต่ละแถวที่ดึงข้อมูลมา ตัวอย่างเช่น หากคุณค้นหา
    ContactsContract.Contacts.Entity สำหรับชื่อรายชื่อติดต่อ
    และแถว ContactsContract.CommonDataKinds.Email ทั้งหมดสำหรับ
    รายชื่อติดต่อดิบทั้งหมดสำหรับชื่อนั้น คุณจะได้รับ Cursor ที่มีแถว 1 แถว
    สำหรับแถว ContactsContract.CommonDataKinds.Email แต่ละแถว
เอนทิตีช่วยให้การค้นหาง่ายขึ้น การใช้เอนทิตีช่วยให้คุณดึงข้อมูลรายชื่อติดต่อทั้งหมดสำหรับ รายชื่อติดต่อหรือรายชื่อติดต่อดิบได้ในครั้งเดียว แทนที่จะต้องค้นหาตารางหลักก่อนเพื่อรับรหัส แล้วจึงต้องค้นหาตารางย่อยด้วยรหัสนั้น นอกจากนี้ ผู้ให้บริการรายชื่อติดต่อยังประมวลผล การค้นหาเทียบกับเอนทิตีในธุรกรรมเดียว ซึ่งช่วยให้มั่นใจว่าข้อมูลที่เรียกคืนมาจะ สอดคล้องกันภายใน
    หมายเหตุ: โดยปกติแล้วเอนทิตีจะไม่มีคอลัมน์ทั้งหมดของตารางหลักและตารางย่อย หากพยายามใช้ชื่อคอลัมน์ที่ไม่ได้อยู่ในรายการค่าคงที่ของชื่อคอลัมน์
    สำหรับเอนทิตี คุณจะได้รับ Exception
    ข้อมูลโค้ดต่อไปนี้แสดงวิธีดึงข้อมูลแถวรายชื่อติดต่อดิบทั้งหมดสำหรับรายชื่อติดต่อ ข้อมูลโค้ด
    เป็นส่วนหนึ่งของแอปพลิเคชันขนาดใหญ่ที่มี 2 กิจกรรม ได้แก่ "main" และ "detail" กิจกรรมหลัก
    แสดงรายการแถวของรายชื่อติดต่อ เมื่อผู้ใช้เลือกแถวใดแถวหนึ่ง กิจกรรมจะส่งรหัสไปยังกิจกรรมรายละเอียด
     กิจกรรมแบบละเอียดใช้ ContactsContract.Contacts.Entity
    เพื่อแสดงแถวข้อมูลทั้งหมดจากรายชื่อติดต่อดิบทั้งหมดที่เชื่อมโยงกับรายชื่อติดต่อที่เลือก
    
ข้อมูลโค้ดนี้มาจากกิจกรรม "รายละเอียด"
Kotlin
... /* * Appends the entity path to the URI. In the case of the Contacts Provider, the * expected URI is content://com.google.contacts/#/entity (# is the ID value). */ contactUri = Uri.withAppendedPath( contactUri, ContactsContract.Contacts.Entity.CONTENT_DIRECTORY ) // Initializes the loader identified by LOADER_ID. loaderManager.initLoader( LOADER_ID, // The identifier of the loader to initialize null, // Arguments for the loader (in this case, none) this // The context of the activity ) // Creates a new cursor adapter to attach to the list view cursorAdapter = SimpleCursorAdapter( this, // the context of the activity R.layout.detail_list_item, // the view item containing the detail widgets mCursor, // the backing cursor fromColumns, // the columns in the cursor that provide the data toViews, // the views in the view item that display the data 0) // flags // Sets the ListView's backing adapter. rawContactList.adapter = cursorAdapter ... override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { /* * Sets the columns to retrieve. * RAW_CONTACT_ID is included to identify the raw contact associated with the data row. * DATA1 contains the first column in the data row (usually the most important one). * MIMETYPE indicates the type of data in the data row. */ val projection: Array<String> = arrayOf( ContactsContract.Contacts.Entity.RAW_CONTACT_ID, ContactsContract.Contacts.Entity.DATA1, ContactsContract.Contacts.Entity.MIMETYPE ) /* * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw * contact collated together. */ val sortOrder = "${ContactsContract.Contacts.Entity.RAW_CONTACT_ID} ASC" /* * Returns a new CursorLoader. The arguments are similar to * ContentResolver.query(), except for the Context argument, which supplies the location of * the ContentResolver to use. */ return CursorLoader( applicationContext, // The activity's context contactUri, // The entity content URI for a single contact projection, // The columns to retrieve null, // Retrieve all the raw contacts and their data rows. null, // sortOrder // Sort by the raw contact ID. ) }
Java
... /* * Appends the entity path to the URI. In the case of the Contacts Provider, the * expected URI is content://com.google.contacts/#/entity (# is the ID value). */ contactUri = Uri.withAppendedPath( contactUri, ContactsContract.Contacts.Entity.CONTENT_DIRECTORY); // Initializes the loader identified by LOADER_ID. getLoaderManager().initLoader( LOADER_ID, // The identifier of the loader to initialize null, // Arguments for the loader (in this case, none) this); // The context of the activity // Creates a new cursor adapter to attach to the list view cursorAdapter = new SimpleCursorAdapter( this, // the context of the activity R.layout.detail_list_item, // the view item containing the detail widgets mCursor, // the backing cursor fromColumns, // the columns in the cursor that provide the data toViews, // the views in the view item that display the data 0); // flags // Sets the ListView's backing adapter. rawContactList.setAdapter(cursorAdapter); ... @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { /* * Sets the columns to retrieve. * RAW_CONTACT_ID is included to identify the raw contact associated with the data row. * DATA1 contains the first column in the data row (usually the most important one). * MIMETYPE indicates the type of data in the data row. */ String[] projection = { ContactsContract.Contacts.Entity.RAW_CONTACT_ID, ContactsContract.Contacts.Entity.DATA1, ContactsContract.Contacts.Entity.MIMETYPE }; /* * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw * contact collated together. */ String sortOrder = ContactsContract.Contacts.Entity.RAW_CONTACT_ID + " ASC"; /* * Returns a new CursorLoader. The arguments are similar to * ContentResolver.query(), except for the Context argument, which supplies the location of * the ContentResolver to use. */ return new CursorLoader( getApplicationContext(), // The activity's context contactUri, // The entity content URI for a single contact projection, // The columns to retrieve null, // Retrieve all the raw contacts and their data rows. null, // sortOrder); // Sort by the raw contact ID. }
    เมื่อโหลดเสร็จแล้ว LoaderManager จะเรียกใช้การเรียกกลับไปยัง
    onLoadFinished() อาร์กิวเมนต์ขาเข้าอย่างหนึ่งของเมธอดนี้คือ
    Cursor ที่มีผลลัพธ์ของคำค้นหา ในแอปของคุณเอง คุณสามารถรับ
    ข้อมูลจาก Cursor นี้เพื่อแสดงหรือทำงานกับข้อมูลเพิ่มเติมได้
การแก้ไขแบบเป็นกลุ่ม
    คุณควรแทรก อัปเดต และลบข้อมูลในผู้ให้บริการรายชื่อติดต่อใน "โหมดกลุ่ม" ทุกครั้งที่ทำได้ โดยการสร้างออบเจ็กต์ ArrayList ของออบเจ็กต์ ContentProviderOperation และเรียกใช้ applyBatch() เนื่องจาก
    ผู้ให้บริการรายชื่อติดต่อจะดำเนินการทั้งหมดใน
    applyBatch() ในธุรกรรมเดียว
    การแก้ไขของคุณจึงจะไม่ทำให้ที่เก็บรายชื่อติดต่ออยู่ในสถานะที่ไม่สอดคล้องกัน
     การแก้ไขแบบเป็นกลุ่มยังช่วยให้แทรกรายชื่อติดต่อดิบและข้อมูลรายละเอียดได้พร้อมกันด้วย
    
หมายเหตุ: หากต้องการแก้ไขรายชื่อติดต่อดิบรายการเดียว ให้ลองส่ง Intent ไปยัง แอปพลิเคชันรายชื่อติดต่อของอุปกรณ์แทนที่จะจัดการการแก้ไขในแอป คุณสามารถดูรายละเอียดเพิ่มเติมเกี่ยวกับวิธีนี้ได้ในส่วน การดึงข้อมูลและการแก้ไขด้วย Intent
จุดหยุดชั่วคราว
    การแก้ไขแบบเป็นชุดที่มีการดำเนินการจำนวนมากอาจบล็อกกระบวนการอื่นๆ
    ซึ่งส่งผลให้ผู้ใช้ได้รับประสบการณ์การใช้งานโดยรวมที่ไม่ดี หากต้องการจัดระเบียบการแก้ไขทั้งหมดที่คุณต้องการ
    ดำเนินการในรายการที่แยกกันให้น้อยที่สุด และในขณะเดียวกันก็ป้องกันไม่ให้
    การแก้ไขเหล่านั้นบล็อกระบบ คุณควรตั้งค่าจุดผลตอบแทนสำหรับการดำเนินการอย่างน้อย 1 รายการ
    จุดที่ให้ผลตอบแทนคือออบเจ็กต์ ContentProviderOperation ที่มีค่า
    isYieldAllowed() ตั้งค่าเป็น
    true เมื่อผู้ให้บริการรายชื่อติดต่อพบจุดที่ต้องหยุดชั่วคราว ผู้ให้บริการจะหยุดการทำงานชั่วคราวเพื่อ
    ให้กระบวนการอื่นๆ ทำงานและปิดธุรกรรมปัจจุบัน เมื่อผู้ให้บริการเริ่มทำงานอีกครั้ง ผู้ให้บริการจะ
    ดำเนินการต่อด้วยการดำเนินการถัดไปใน ArrayList และเริ่มธุรกรรมใหม่
    
    คะแนนผลตอบแทนจะทำให้เกิดธุรกรรมมากกว่า 1 รายการต่อการเรียกใช้
    applyBatch() ด้วยเหตุนี้ คุณจึงควรตั้งค่าจุดหยุดชั่วคราวสำหรับการดำเนินการสุดท้ายของชุดแถวที่เกี่ยวข้อง
    เช่น คุณควรตั้งค่าจุดผลตอบแทนสำหรับการดำเนินการสุดท้ายในชุดที่เพิ่ม
    แถวรายชื่อติดต่อดิบและแถวข้อมูลที่เชื่อมโยง หรือการดำเนินการสุดท้ายสำหรับชุดแถวที่เกี่ยวข้อง
    กับรายชื่อติดต่อเดียว
นอกจากนี้ จุดผลตอบแทนยังเป็นหน่วยของการดำเนินการแบบอะตอมมิกด้วย การเข้าถึงทั้งหมดระหว่างจุดให้ผลตอบแทน 2 จุดจะ สำเร็จหรือล้มเหลวเป็นหน่วยเดียว หากไม่ได้ตั้งค่าจุดให้ผล การดำเนินการย่อยที่เล็กที่สุด คือชุดการดำเนินการทั้งหมด หากใช้จุดผลตอบแทน คุณจะป้องกันไม่ให้ การดำเนินการทำให้ประสิทธิภาพของระบบลดลง ในขณะเดียวกันก็มั่นใจได้ว่าการดำเนินการย่อยของ การดำเนินการจะเป็นแบบอะตอม
การอ้างอิงย้อนกลับของการแก้ไข
    เมื่อแทรกแถวรายชื่อติดต่อดิบใหม่และแถวข้อมูลที่เชื่อมโยงเป็นชุดของออบเจ็กต์ ContentProviderOperation คุณต้องลิงก์แถวข้อมูลกับแถวรายชื่อติดต่อดิบโดยแทรกค่า _ID ของรายชื่อติดต่อดิบเป็นค่า RAW_CONTACT_ID อย่างไรก็ตาม ค่านี้จะไม่พร้อมใช้งานเมื่อคุณสร้าง ContentProviderOperation
    สำหรับแถวข้อมูล เนื่องจากคุณยังไม่ได้ใช้ ContentProviderOperation
    สำหรับแถวรายชื่อติดต่อดิบ หากต้องการหลีกเลี่ยงปัญหานี้
    คลาส ContentProviderOperation.Builder มีเมธอด
    withValueBackReference()
    วิธีนี้ช่วยให้คุณแทรกหรือแก้ไขคอลัมน์ที่มี
    ผลลัพธ์ของการดำเนินการก่อนหน้าได้
    เมธอด withValueBackReference()
    มีอาร์กิวเมนต์ 2 รายการ ดังนี้
- 
            key
- คีย์ของคู่คีย์-ค่า ค่าของอาร์กิวเมนต์นี้ควรเป็นชื่อของคอลัมน์ ในตารางที่คุณกำลังแก้ไข
- 
            previousResult
- 
            ดัชนีแบบ 0 ของค่าในอาร์เรย์ของออบเจ็กต์
            ContentProviderResultจากapplyBatch()เมื่อ ใช้การดำเนินการแบบกลุ่ม ระบบจะจัดเก็บผลลัพธ์ของการดำเนินการแต่ละรายการไว้ใน อาร์เรย์ผลลัพธ์ชั่วคราว ค่าpreviousResultคือดัชนี ของผลลัพธ์อย่างใดอย่างหนึ่งต่อไปนี้ ซึ่งจะเรียกและจัดเก็บพร้อมกับค่าkeyซึ่งจะช่วยให้คุณแทรกระเบียนรายชื่อติดต่อดิบใหม่และรับค่า_IDกลับมา จากนั้นสร้าง "การอ้างอิงย้อนกลับ" ไปยังค่าเมื่อเพิ่มแถวContactsContract.Dataระบบจะสร้างอาร์เรย์ผลลัพธ์ทั้งหมดเมื่อคุณเรียกใช้ applyBatch(), เป็นครั้งแรก โดยมีขนาดเท่ากับขนาดของArrayListของออบเจ็กต์ContentProviderOperationที่คุณระบุ อย่างไรก็ตาม ระบบจะตั้งค่าองค์ประกอบทั้งหมดในอาร์เรย์ผลลัพธ์เป็นnullและหากคุณพยายาม อ้างอิงย้อนกลับไปยังผลลัพธ์สำหรับการดำเนินการที่ยังไม่ได้ใช้withValueBackReference()ระบบจะแสดงException
ข้อมูลโค้ดต่อไปนี้แสดงวิธีแทรกรายชื่อติดต่อดิบและข้อมูลใหม่เป็นกลุ่ม โดยมีโค้ดที่กำหนดจุดที่ได้ผลตอบแทนและใช้การอ้างอิงย้อนกลับ
ข้อมูลโค้ดแรกจะดึงข้อมูลรายชื่อติดต่อจาก UI ในขั้นตอนนี้ ผู้ใช้ได้เลือกบัญชีที่จะเพิ่มรายชื่อติดต่อดิบใหม่แล้ว
Kotlin
// Creates a contact entry from the current UI values, using the currently-selected account. private fun createContactEntry() { /* * Gets values from the UI */ val name = contactNameEditText.text.toString() val phone = contactPhoneEditText.text.toString() val email = contactEmailEditText.text.toString() val phoneType: String = contactPhoneTypes[mContactPhoneTypeSpinner.selectedItemPosition] val emailType: String = contactEmailTypes[mContactEmailTypeSpinner.selectedItemPosition]
Java
// Creates a contact entry from the current UI values, using the currently-selected account. protected void createContactEntry() { /* * Gets values from the UI */ String name = contactNameEditText.getText().toString(); String phone = contactPhoneEditText.getText().toString(); String email = contactEmailEditText.getText().toString(); int phoneType = contactPhoneTypes.get( contactPhoneTypeSpinner.getSelectedItemPosition()); int emailType = contactEmailTypes.get( contactEmailTypeSpinner.getSelectedItemPosition());
    ข้อมูลโค้ดถัดไปจะสร้างการดำเนินการเพื่อแทรกแถวรายชื่อติดต่อดิบลงในตาราง
    ContactsContract.RawContacts
Kotlin
/* * Prepares the batch operation for inserting a new raw contact and its data. Even if * the Contacts Provider does not have any data for this person, you can't add a Contact, * only a raw contact. The Contacts Provider will then add a Contact automatically. */ // Creates a new array of ContentProviderOperation objects. val ops = arrayListOf<ContentProviderOperation>() /* * Creates a new raw contact with its account type (server type) and account name * (user's account). Remember that the display name is not stored in this row, but in a * StructuredName data row. No other data is required. */ var op: ContentProviderOperation.Builder = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.name) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.type) // Builds the operation and adds it to the array of operations ops.add(op.build())
Java
/* * Prepares the batch operation for inserting a new raw contact and its data. Even if * the Contacts Provider does not have any data for this person, you can't add a Contact, * only a raw contact. The Contacts Provider will then add a Contact automatically. */ // Creates a new array of ContentProviderOperation objects. ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); /* * Creates a new raw contact with its account type (server type) and account name * (user's account). Remember that the display name is not stored in this row, but in a * StructuredName data row. No other data is required. */ ContentProviderOperation.Builder op = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.getType()) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.getName()); // Builds the operation and adds it to the array of operations ops.add(op.build());
จากนั้นโค้ดจะสร้างแถวข้อมูลสำหรับแถวชื่อที่แสดง โทรศัพท์ และอีเมล
    ออบเจ็กต์เครื่องมือสร้างการดำเนินการแต่ละรายการใช้
    withValueBackReference()
    เพื่อรับ
    RAW_CONTACT_ID จุดอ้างอิง
    กลับไปยังออบเจ็กต์ ContentProviderResult จากการดำเนินการแรก
    ซึ่งจะเพิ่มแถวรายชื่อติดต่อดิบและแสดงผลค่า _ID
    ใหม่ ด้วยเหตุนี้ ระบบจึงลิงก์แถวข้อมูลแต่ละแถวโดยอัตโนมัติด้วย
    RAW_CONTACT_ID
    ไปยังแถว ContactsContract.RawContacts ใหม่ที่แถวนั้นเป็นของ
    ออบเจ็กต์ ContentProviderOperation.Builder ที่เพิ่มแถวอีเมลจะ
    มีการแจ้งว่า withYieldAllowed() ซึ่งจะตั้งค่าจุดที่ให้ผลตอบแทน
Kotlin
// Creates the display name for the new raw contact, as a StructuredName data row. op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * withValueBackReference sets the value of the first argument to the value of * the ContentProviderResult indexed by the second argument. In this particular * call, the raw contact ID column of the StructuredName data row is set to the * value of the result returned by the first operation, which is the one that * actually adds the raw contact row. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to StructuredName .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) // Sets the data row's display name to the name in the UI. .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name) // Builds the operation and adds it to the array of operations ops.add(op.build()) // Inserts the specified phone number and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Phone .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Sets the phone number and type .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType) // Builds the operation and adds it to the array of operations ops.add(op.build()) // Inserts the specified email and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Email .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Sets the email address and type .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType) /* * Demonstrates a yield point. At the end of this insert, the batch operation's thread * will yield priority to other threads. Use after every set of operations that affect a * single contact, to avoid degrading performance. */ op.withYieldAllowed(true) // Builds the operation and adds it to the array of operations ops.add(op.build())
Java
// Creates the display name for the new raw contact, as a StructuredName data row. op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * withValueBackReference sets the value of the first argument to the value of * the ContentProviderResult indexed by the second argument. In this particular * call, the raw contact ID column of the StructuredName data row is set to the * value of the result returned by the first operation, which is the one that * actually adds the raw contact row. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to StructuredName .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) // Sets the data row's display name to the name in the UI. .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name); // Builds the operation and adds it to the array of operations ops.add(op.build()); // Inserts the specified phone number and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Phone .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Sets the phone number and type .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType); // Builds the operation and adds it to the array of operations ops.add(op.build()); // Inserts the specified email and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Email .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Sets the email address and type .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType); /* * Demonstrates a yield point. At the end of this insert, the batch operation's thread * will yield priority to other threads. Use after every set of operations that affect a * single contact, to avoid degrading performance. */ op.withYieldAllowed(true); // Builds the operation and adds it to the array of operations ops.add(op.build());
    ข้อมูลโค้ดสุดท้ายแสดงการเรียกใช้
    applyBatch() ที่
    แทรกรายชื่อติดต่อและแถวข้อมูลใหม่
Kotlin
// Ask the Contacts Provider to create a new contact Log.d(TAG, "Selected account: ${mSelectedAccount.name} (${mSelectedAccount.type})") Log.d(TAG, "Creating contact: $name") /* * Applies the array of ContentProviderOperation objects in batch. The results are * discarded. */ try { contentResolver.applyBatch(ContactsContract.AUTHORITY, ops) } catch (e: Exception) { // Display a warning val txt: String = getString(R.string.contactCreationFailure) Toast.makeText(applicationContext, txt, Toast.LENGTH_SHORT).show() // Log exception Log.e(TAG, "Exception encountered while inserting contact: $e") } }
Java
// Ask the Contacts Provider to create a new contact Log.d(TAG,"Selected account: " + selectedAccount.getName() + " (" + selectedAccount.getType() + ")"); Log.d(TAG,"Creating contact: " + name); /* * Applies the array of ContentProviderOperation objects in batch. The results are * discarded. */ try { getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); } catch (Exception e) { // Display a warning Context ctx = getApplicationContext(); CharSequence txt = getString(R.string.contactCreationFailure); int duration = Toast.LENGTH_SHORT; Toast toast = Toast.makeText(ctx, txt, duration); toast.show(); // Log exception Log.e(TAG, "Exception encountered while inserting contact: " + e); } }
การดำเนินการแบบกลุ่มยังช่วยให้คุณใช้การควบคุมการทำงานพร้อมกันแบบมองโลกในแง่ดีได้ด้วย ซึ่งเป็นวิธีการใช้ธุรกรรมการแก้ไขโดยไม่ต้องล็อกที่เก็บข้อมูลพื้นฐาน หากต้องการใช้วิธีนี้ ให้ใช้ธุรกรรม แล้วตรวจสอบการแก้ไขอื่นๆ ที่อาจเกิดขึ้นพร้อมกัน หากพบว่ามีการแก้ไขที่ไม่สอดคล้องกันเกิดขึ้น คุณ สามารถย้อนกลับธุรกรรมและลองอีกครั้ง
การควบคุมการทำงานพร้อมกันแบบมองโลกในแง่ดีมีประโยชน์สำหรับอุปกรณ์เคลื่อนที่ ซึ่งมีผู้ใช้เพียงคนเดียวในแต่ละครั้ง และการเข้าถึงที่เก็บข้อมูลพร้อมกันนั้นเกิดขึ้นได้ยาก เนื่องจากไม่ได้ใช้การล็อก จึงไม่ต้องเสียเวลาในการตั้งค่าการล็อกหรือรอให้ธุรกรรมอื่นๆ ปลดล็อก
    หากต้องการใช้การควบคุมการทำงานพร้อมกันแบบมองโลกในแง่ดีขณะอัปเดตแถวเดียว
    ContactsContract.RawContacts ให้ทำตามขั้นตอนต่อไปนี้
- 
        เรียกข้อมูลคอลัมน์ VERSIONของรายชื่อติดต่อดิบพร้อมกับข้อมูลอื่นๆ ที่คุณเรียก
- 
        สร้างออบเจ็กต์ ContentProviderOperation.Builderที่เหมาะสำหรับ การบังคับใช้ข้อจำกัดโดยใช้วิธีการnewAssertQuery(Uri)สำหรับ URI ของเนื้อหา ให้ใช้RawContacts.CONTENT_URIโดยต่อท้ายด้วย_IDของรายชื่อติดต่อดิบ
- 
        สำหรับออบเจ็กต์ ContentProviderOperation.Builderให้เรียกใช้withValue()เพื่อเปรียบเทียบคอลัมน์VERSIONกับหมายเลขเวอร์ชันที่คุณเพิ่งดึงข้อมูลมา
- 
        สำหรับ ContentProviderOperation.Builderเดียวกัน ให้เรียกใช้withExpectedCount()เพื่อให้แน่ใจว่าการยืนยันนี้จะทดสอบเพียงแถวเดียว
- 
        เรียกใช้ build()เพื่อสร้างออบเจ็กต์ContentProviderOperationจากนั้นเพิ่มออบเจ็กต์นี้เป็นออบเจ็กต์แรกในArrayListที่คุณส่งไปยังapplyBatch()
- ใช้ธุรกรรมแบบกลุ่ม
    หากมีการอัปเดตแถวของข้อมูลติดต่อดิบโดยการดำเนินการอื่นระหว่างเวลาที่คุณอ่านแถวกับ
    เวลาที่คุณพยายามแก้ไข "ยืนยัน" ContentProviderOperation
    จะล้มเหลว และระบบจะยกเลิกการดำเนินการทั้งหมดในกลุ่ม จากนั้นคุณสามารถเลือกที่จะลองส่ง
    กลุ่มอีกครั้งหรือดำเนินการอื่นๆ
    ข้อมูลโค้ดต่อไปนี้แสดงวิธีสร้าง "assert"
    ContentProviderOperation หลังจากค้นหารายชื่อติดต่อดิบรายการเดียวโดยใช้
    CursorLoader
Kotlin
/* * The application uses CursorLoader to query the raw contacts table. The system calls this method * when the load is finished. */ override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) { // Gets the raw contact's _ID and VERSION values rawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID)) mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION)) } ... // Sets up a Uri for the assert operation val rawContactUri: Uri = ContentUris.withAppendedId( ContactsContract.RawContacts.CONTENT_URI, rawContactID ) // Creates a builder for the assert operation val assertOp: ContentProviderOperation.Builder = ContentProviderOperation.newAssertQuery(rawContactUri).apply { // Adds the assertions to the assert operation: checks the version withValue(SyncColumns.VERSION, mVersion) // and count of rows tested withExpectedCount(1) } // Creates an ArrayList to hold the ContentProviderOperation objects val ops = arrayListOf<ContentProviderOperation>() ops.add(assertOp.build()) // You would add the rest of your batch operations to "ops" here ... // Applies the batch. If the assert fails, an Exception is thrown try { val results: Array<ContentProviderResult> = contentResolver.applyBatch(AUTHORITY, ops) } catch (e: OperationApplicationException) { // Actions you want to take if the assert operation fails go here }
Java
/* * The application uses CursorLoader to query the raw contacts table. The system calls this method * when the load is finished. */ public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { // Gets the raw contact's _ID and VERSION values rawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID)); mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION)); } ... // Sets up a Uri for the assert operation Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactID); // Creates a builder for the assert operation ContentProviderOperation.Builder assertOp = ContentProviderOperation.newAssertQuery(rawContactUri); // Adds the assertions to the assert operation: checks the version and count of rows tested assertOp.withValue(SyncColumns.VERSION, mVersion); assertOp.withExpectedCount(1); // Creates an ArrayList to hold the ContentProviderOperation objects ArrayList ops = new ArrayList<ContentProviderOperation>; ops.add(assertOp.build()); // You would add the rest of your batch operations to "ops" here ... // Applies the batch. If the assert fails, an Exception is thrown try { ContentProviderResult[] results = getContentResolver().applyBatch(AUTHORITY, ops); } catch (OperationApplicationException e) { // Actions you want to take if the assert operation fails go here }
การดึงข้อมูลและการแก้ไขด้วย Intent
การส่ง Intent ไปยังแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์จะช่วยให้คุณเข้าถึง Contacts Provider โดยอ้อมได้ Intent จะเริ่ม UI ของแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ ซึ่งผู้ใช้สามารถ ทำงานที่เกี่ยวข้องกับรายชื่อติดต่อได้ เมื่อมีสิทธิ์เข้าถึงประเภทนี้ ผู้ใช้จะทำสิ่งต่อไปนี้ได้
- เลือกรายชื่อติดต่อจากรายการและส่งกลับไปยังแอปของคุณเพื่อดำเนินการต่อ
- แก้ไขข้อมูลของผู้ติดต่อที่มีอยู่
- แทรกรายชื่อติดต่อดิบใหม่สำหรับบัญชีใดก็ได้
- ลบรายชื่อติดต่อหรือข้อมูลรายชื่อติดต่อ
หากผู้ใช้แทรกหรืออัปเดตข้อมูล คุณสามารถรวบรวมข้อมูลก่อนแล้วส่งเป็น ส่วนหนึ่งของ Intent ได้
เมื่อใช้ Intent เพื่อเข้าถึงผู้ให้บริการรายชื่อติดต่อผ่านแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ คุณ ไม่จำเป็นต้องเขียน UI หรือโค้ดของคุณเองเพื่อเข้าถึงผู้ให้บริการ นอกจากนี้ คุณยังไม่จำเป็นต้อง ขอสิทธิ์อ่านหรือเขียนไปยังผู้ให้บริการ แอปพลิเคชันรายชื่อติดต่อของอุปกรณ์สามารถ มอบสิทธิ์อ่านรายชื่อติดต่อให้คุณได้ และเนื่องจากคุณทำการแก้ไขผู้ให้บริการผ่านแอปพลิเคชันอื่น คุณจึงไม่จำเป็นต้องมีสิทธิ์เขียน
    กระบวนการทั่วไปในการส่ง Intent เพื่อเข้าถึงผู้ให้บริการอธิบายไว้โดยละเอียดใน
    
    คู่มือข้อมูลเบื้องต้นเกี่ยวกับผู้ให้บริการเนื้อหาในส่วน "การเข้าถึงข้อมูลผ่าน Intent" การดำเนินการ
    ประเภท MIME และค่าข้อมูลที่คุณใช้สำหรับงานที่พร้อมใช้งานจะสรุปไว้ในตารางที่ 4 ส่วนค่า
    extras ที่คุณใช้กับ
    putExtra() จะแสดงอยู่ใน
    เอกสารอ้างอิงสำหรับ ContactsContract.Intents.Insert
ตารางที่ 4 เจตนาของ Contacts Provider
| งาน | การทำงาน | ข้อมูล | ประเภท MIME | หมายเหตุ | 
|---|---|---|---|---|
| เลือกรายชื่อติดต่อจากรายการ | ACTION_PICK | ค่าใดค่าหนึ่งต่อไปนี้ 
 | ไม่ใช้ | แสดงรายการรายชื่อติดต่อดิบหรือรายการข้อมูลจากรายชื่อติดต่อดิบ ทั้งนี้ขึ้นอยู่กับ
            ประเภท URI ของเนื้อหาที่คุณระบุ 
                Call
          | 
| แทรกรายชื่อติดต่อดิบใหม่ | Insert.ACTION | ไม่มี | RawContacts.CONTENT_TYPEประเภท MIME สำหรับชุดรายชื่อติดต่อดิบ | แสดงหน้าจอเพิ่มรายชื่อติดต่อของแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ ค่า
            extras ที่คุณเพิ่มลงใน Intent จะแสดงขึ้น หากส่งพร้อมกับ startActivityForResult()ระบบจะส่ง URI ของเนื้อหาของรายชื่อติดต่อดิบที่เพิ่มใหม่กลับไปยังเมธอดเรียกกลับonActivityResult()ของกิจกรรมในอาร์กิวเมนต์Intentในฟิลด์ "data"
 หากต้องการทราบค่าดังกล่าว โปรดโทรหาgetData() | 
| แก้ไขรายชื่อติดต่อ | ACTION_EDIT | CONTENT_LOOKUP_URIสำหรับ
            รายชื่อติดต่อ กิจกรรมของเอดิเตอร์จะช่วยให้ผู้ใช้แก้ไขข้อมูลที่เชื่อมโยงกับรายชื่อติดต่อนี้ได้ | Contacts.CONTENT_ITEM_TYPEรายชื่อติดต่อเดียว | แสดงหน้าจอแก้ไขรายชื่อติดต่อในแอปพลิเคชันรายชื่อติดต่อ ค่าพิเศษที่คุณเพิ่ม ลงใน Intent จะแสดงขึ้น เมื่อผู้ใช้คลิกเสร็จสิ้นเพื่อบันทึก การแก้ไข กิจกรรมของคุณจะกลับมาอยู่เบื้องหน้า | 
| แสดงเครื่องมือเลือกที่เพิ่มข้อมูลได้ด้วย | ACTION_INSERT_OR_EDIT | ไม่มี | CONTENT_ITEM_TYPE | ความตั้งใจนี้จะแสดงหน้าจอเครื่องมือเลือกของแอปรายชื่อติดต่อเสมอ ผู้ใช้สามารถ
            เลือกรายชื่อติดต่อที่จะแก้ไข หรือเพิ่มรายชื่อติดต่อใหม่ หน้าจอแก้ไขหรือหน้าจอเพิ่มจะปรากฏขึ้น ทั้งนี้ขึ้นอยู่กับตัวเลือกของผู้ใช้ และระบบจะแสดงข้อมูลเพิ่มเติมที่คุณส่งใน Intent
             หากแอปแสดงข้อมูลติดต่อ เช่น อีเมลหรือหมายเลขโทรศัพท์ ให้ใช้
            Intent นี้เพื่อให้ผู้ใช้เพิ่มข้อมูลลงในรายชื่อติดต่อที่มีอยู่
            รายชื่อติดต่อ หมายเหตุ: ไม่จำเป็นต้องส่งค่าชื่อในส่วนพิเศษของ Intent นี้ เนื่องจากผู้ใช้จะเลือกชื่อที่มีอยู่หรือเพิ่มชื่อใหม่เสมอ นอกจากนี้ หากคุณส่งชื่อและผู้ใช้เลือกที่จะแก้ไข แอปรายชื่อติดต่อจะ แสดงชื่อที่คุณส่งและเขียนทับค่าก่อนหน้า หากผู้ใช้ไม่สังเกตเห็นข้อความนี้และบันทึกการแก้ไข ค่าเก่าจะหายไป | 
    แอปรายชื่อติดต่อของอุปกรณ์ไม่อนุญาตให้คุณลบรายชื่อติดต่อดิบหรือข้อมูลใดๆ ของรายชื่อติดต่อดังกล่าวด้วย
    Intent แต่หากต้องการลบรายชื่อติดต่อดิบ ให้ใช้
    ContentResolver.delete()
    หรือ ContentProviderOperation.newDelete()
ข้อมูลโค้ดต่อไปนี้แสดงวิธีสร้างและส่ง Intent ที่แทรกรายชื่อติดต่อและข้อมูลใหม่
Kotlin
// Gets values from the UI val name = contactNameEditText.text.toString() val phone = contactPhoneEditText.text.toString() val email = contactEmailEditText.text.toString() val company = companyName.text.toString() val jobtitle = jobTitle.text.toString() /* * Demonstrates adding data rows as an array list associated with the DATA key */ // Defines an array list to contain the ContentValues objects for each row val contactData = arrayListOf<ContentValues>() /* * Defines the raw contact row */ // Sets up the row as a ContentValues object val rawContactRow = ContentValues().apply { // Adds the account type and name to the row put(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.type) put(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.name) } // Adds the row to the array contactData.add(rawContactRow) /* * Sets up the phone number data row */ // Sets up the row as a ContentValues object val phoneRow = ContentValues().apply { // Specifies the MIME type for this data row (all data rows must be marked by their type) put(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Adds the phone number and its type to the row put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) } // Adds the row to the array contactData.add(phoneRow) /* * Sets up the email data row */ // Sets up the row as a ContentValues object val emailRow = ContentValues().apply { // Specifies the MIME type for this data row (all data rows must be marked by their type) put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Adds the email address and its type to the row put(ContactsContract.CommonDataKinds.Email.ADDRESS, email) } // Adds the row to the array contactData.add(emailRow) // Creates a new intent for sending to the device's contacts application val insertIntent = Intent(ContactsContract.Intents.Insert.ACTION).apply { // Sets the MIME type to the one expected by the insertion activity type = ContactsContract.RawContacts.CONTENT_TYPE // Sets the new contact name putExtra(ContactsContract.Intents.Insert.NAME, name) // Sets the new company and job title putExtra(ContactsContract.Intents.Insert.COMPANY, company) putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle) /* * Adds the array to the intent's extras. It must be a parcelable object in order to * travel between processes. The device's contacts app expects its key to be * Intents.Insert.DATA */ putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData) } // Send out the intent to start the device's contacts app in its add contact activity. startActivity(insertIntent)
Java
// Gets values from the UI String name = contactNameEditText.getText().toString(); String phone = contactPhoneEditText.getText().toString(); String email = contactEmailEditText.getText().toString(); String company = companyName.getText().toString(); String jobtitle = jobTitle.getText().toString(); // Creates a new intent for sending to the device's contacts application Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION); // Sets the MIME type to the one expected by the insertion activity insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE); // Sets the new contact name insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name); // Sets the new company and job title insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company); insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle); /* * Demonstrates adding data rows as an array list associated with the DATA key */ // Defines an array list to contain the ContentValues objects for each row ArrayList<ContentValues> contactData = new ArrayList<ContentValues>(); /* * Defines the raw contact row */ // Sets up the row as a ContentValues object ContentValues rawContactRow = new ContentValues(); // Adds the account type and name to the row rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.getType()); rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.getName()); // Adds the row to the array contactData.add(rawContactRow); /* * Sets up the phone number data row */ // Sets up the row as a ContentValues object ContentValues phoneRow = new ContentValues(); // Specifies the MIME type for this data row (all data rows must be marked by their type) phoneRow.put( ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE ); // Adds the phone number and its type to the row phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone); // Adds the row to the array contactData.add(phoneRow); /* * Sets up the email data row */ // Sets up the row as a ContentValues object ContentValues emailRow = new ContentValues(); // Specifies the MIME type for this data row (all data rows must be marked by their type) emailRow.put( ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE ); // Adds the email address and its type to the row emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email); // Adds the row to the array contactData.add(emailRow); /* * Adds the array to the intent's extras. It must be a parcelable object in order to * travel between processes. The device's contacts app expects its key to be * Intents.Insert.DATA */ insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData); // Send out the intent to start the device's contacts app in its add contact activity. startActivity(insertIntent);
ความสมบูรณ์ของข้อมูล
เนื่องจากที่เก็บรายชื่อติดต่อมีข้อมูลที่สำคัญและละเอียดอ่อนซึ่งผู้ใช้คาดหวังว่าข้อมูลดังกล่าวจะถูกต้องและเป็นปัจจุบัน ผู้ให้บริการรายชื่อติดต่อจึงมีกฎที่กำหนดไว้อย่างชัดเจนสำหรับความสมบูรณ์ของข้อมูล คุณมีหน้าที่รับผิดชอบในการปฏิบัติตามกฎเหล่านี้เมื่อแก้ไขข้อมูลรายชื่อติดต่อ กฎที่สำคัญ มีดังนี้
- 
        เพิ่มContactsContract.CommonDataKinds.StructuredNameแถว สําหรับContactsContract.RawContactsแถวทุกแถวที่คุณเพิ่มเสมอ
- 
        แถว ContactsContract.RawContactsที่ไม่มีแถวContactsContract.CommonDataKinds.StructuredNameในตารางContactsContract.Dataอาจทำให้เกิดปัญหาในระหว่างการ รวม
- 
        ลิงก์แถวใหม่ของ ContactsContract.DataกับแถวหลักContactsContract.RawContactsเสมอ
- 
        แถว ContactsContract.Dataที่ไม่ได้ลิงก์กับContactsContract.RawContactsจะไม่ปรากฏในแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ และอาจทำให้เกิดปัญหากับตัวดัดแปลงการซิงค์
- เปลี่ยนข้อมูลเฉพาะสำหรับรายชื่อติดต่อดิบที่คุณเป็นเจ้าของเท่านั้น
- โปรดทราบว่าโดยปกติแล้วผู้ให้บริการรายชื่อติดต่อจะจัดการข้อมูลจากบัญชีประเภทต่างๆ และบริการออนไลน์หลายรายการ คุณต้องตรวจสอบว่าแอปพลิเคชันของคุณแก้ไข หรือลบข้อมูลสำหรับแถวที่เป็นของคุณเท่านั้น และแทรกข้อมูลที่มี ประเภทบัญชีและชื่อที่คุณควบคุมเท่านั้น
- 
        ใช้ค่าคงที่ที่กำหนดไว้ใน ContactsContractและคลาสย่อย ของค่าคงที่นั้นเสมอสำหรับค่าคงที่ของหน่วยงาน, URI ของเนื้อหา, เส้นทาง URI, ชื่อคอลัมน์, ประเภท MIME และค่าTYPE
- การใช้ค่าคงที่เหล่านี้จะช่วยให้คุณหลีกเลี่ยงข้อผิดพลาดได้ นอกจากนี้ คุณจะได้รับการแจ้งเตือนพร้อมคำเตือนของคอมไพเลอร์ หากค่าคงที่ใดค่าหนึ่งเลิกใช้งานแล้ว
แถวข้อมูลที่กำหนดเอง
    การสร้างและใช้ประเภท MIME ที่กำหนดเองจะช่วยให้คุณแทรก แก้ไข ลบ และเรียกข้อมูลแถวข้อมูลของคุณเองในตาราง ContactsContract.Data ได้ แถวของคุณ
    จะใช้ได้เฉพาะคอลัมน์ที่กำหนดไว้ใน
    ContactsContract.DataColumns แม้ว่าคุณจะแมปชื่อคอลัมน์เฉพาะประเภทของคุณเอง
    กับชื่อคอลัมน์เริ่มต้นได้ก็ตาม ในแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์
    ระบบจะแสดงข้อมูลสำหรับแถวของคุณ แต่จะแก้ไขหรือลบไม่ได้ และผู้ใช้จะเพิ่ม
    ข้อมูลเพิ่มเติมไม่ได้ หากต้องการอนุญาตให้ผู้ใช้แก้ไขแถวข้อมูลที่กำหนดเอง คุณต้องระบุกิจกรรมของเอดิเตอร์
    ในแอปพลิเคชันของคุณเอง
    หากต้องการแสดงข้อมูลที่กำหนดเอง ให้ระบุcontacts.xmlไฟล์ที่มีองค์ประกอบ <ContactsAccountType> และองค์ประกอบย่อย <ContactsDataKind> อย่างน้อย 1 รายการ ซึ่งอธิบายไว้อย่างละเอียดในส่วน<ContactsDataKind> element
ดูข้อมูลเพิ่มเติมเกี่ยวกับประเภท MIME ที่กำหนดเองได้ในคู่มือ สร้าง Content Provider
อะแดปเตอร์การซิงค์ Contacts Provider
ผู้ให้บริการรายชื่อติดต่อออกแบบมาเพื่อจัดการการซิงค์ ข้อมูลรายชื่อติดต่อระหว่างอุปกรณ์และบริการออนไลน์โดยเฉพาะ ซึ่งจะช่วยให้ผู้ใช้ดาวน์โหลด ข้อมูลที่มีอยู่ไปยังอุปกรณ์ใหม่และอัปโหลดข้อมูลที่มีอยู่ไปยังบัญชีใหม่ได้ การซิงค์ยังช่วยให้ผู้ใช้มีข้อมูลล่าสุดพร้อมใช้งานเสมอ ไม่ว่า แหล่งที่มาของการเพิ่มและการเปลี่ยนแปลงจะเป็นอะไรก็ตาม ข้อดีอีกอย่างของการซิงค์คือการทำให้ข้อมูลรายชื่อติดต่อพร้อมใช้งานแม้ว่าอุปกรณ์จะไม่ได้เชื่อมต่อกับเครือข่ายก็ตาม
แม้ว่าคุณจะใช้การซิงค์ได้หลายวิธี แต่ระบบ Android มี เฟรมเวิร์กการซิงค์แบบปลั๊กอินที่ทำให้งานต่อไปนี้เป็นไปโดยอัตโนมัติ
- กำลังตรวจสอบความพร้อมใช้งานของเครือข่าย
- การกำหนดเวลาและดำเนินการซิงค์ตามค่ากำหนดของผู้ใช้
- การรีสตาร์ทการซิงโครไนซ์ที่หยุดไป
หากต้องการใช้เฟรมเวิร์กนี้ คุณต้องจัดหาปลั๊กอิน Sync Adapter Sync Adapter แต่ละตัวจะเฉพาะเจาะจงสำหรับผู้ให้บริการและผู้ให้บริการเนื้อหา แต่สามารถจัดการชื่อบัญชีหลายชื่อสำหรับบริการเดียวกันได้ เฟรมเวิร์กยังอนุญาตให้มี Sync Adapter หลายรายการสำหรับบริการและผู้ให้บริการเดียวกันด้วย
คลาสและไฟล์ของอะแดปเตอร์การซิงค์
    คุณใช้ตัวปรับการซิงค์เป็นคลาสย่อยของ
    AbstractThreadedSyncAdapter และติดตั้งเป็นส่วนหนึ่งของแอปพลิเคชัน Android
     ระบบจะเรียนรู้เกี่ยวกับ Sync Adapter จากองค์ประกอบในไฟล์ Manifest ของแอปพลิเคชัน
    และจากไฟล์ XML พิเศษที่ไฟล์ Manifest ชี้ไป ไฟล์ XML จะกำหนด
    ประเภทบัญชีสำหรับบริการออนไลน์และสิทธิ์สำหรับผู้ให้บริการเนื้อหา ซึ่งเมื่อรวมกันแล้ว
    จะระบุอะแดปเตอร์ได้อย่างไม่ซ้ำกัน ตัวปรับการซิงค์จะไม่ทำงานจนกว่าผู้ใช้จะเพิ่มบัญชีสำหรับประเภทบัญชีของตัวปรับการซิงค์และเปิดใช้การซิงค์สำหรับผู้ให้บริการเนื้อหาที่ตัวปรับการซิงค์ซิงค์ด้วย  ในตอนนี้ ระบบจะเริ่มจัดการอแดปเตอร์
    โดยเรียกใช้อแดปเตอร์ตามความจำเป็นเพื่อซิงค์ระหว่างผู้ให้บริการเนื้อหากับเซิร์ฟเวอร์
    หมายเหตุ: การใช้ประเภทบัญชีเป็นส่วนหนึ่งของการระบุตัวตนของ Sync Adapter จะช่วยให้ระบบตรวจหาและจัดกลุ่ม Sync Adapter ที่เข้าถึงบริการต่างๆ จากองค์กรเดียวกันได้ เช่น อะแดปเตอร์การซิงค์สำหรับบริการออนไลน์ของ Google ทั้งหมดมี
    ประเภทบัญชีcom.googleเดียวกัน เมื่อผู้ใช้เพิ่มบัญชี Google ลงในอุปกรณ์ ระบบจะแสดงตัวปรับการซิงค์ที่ติดตั้งไว้ทั้งหมดสำหรับบริการของ Google ไว้ด้วยกัน โดยตัวปรับการซิงค์แต่ละรายการที่แสดงจะซิงค์กับผู้ให้บริการเนื้อหาที่แตกต่างกันในอุปกรณ์
    เนื่องจากบริการส่วนใหญ่กำหนดให้ผู้ใช้ยืนยันตัวตนก่อนจึงจะเข้าถึงข้อมูลได้ ระบบ Android จึงมีเฟรมเวิร์กการตรวจสอบสิทธิ์ที่คล้ายกับเฟรมเวิร์กอะแดปเตอร์การซิงค์ และมักใช้ร่วมกับเฟรมเวิร์กอะแดปเตอร์การซิงค์ เฟรมเวิร์กการตรวจสอบสิทธิ์ใช้
    เครื่องมือตรวจสอบสิทธิ์แบบปลั๊กอินซึ่งเป็นคลาสย่อยของ
    AbstractAccountAuthenticator เครื่องมือตรวจสอบสิทธิ์จะยืนยัน
    ตัวตนของผู้ใช้ในขั้นตอนต่อไปนี้
    
- รวบรวมชื่อ รหัสผ่าน หรือข้อมูลที่คล้ายกันของผู้ใช้ (ข้อมูลเข้าสู่ระบบของผู้ใช้ )
- ส่งข้อมูลเข้าสู่ระบบไปยังบริการ
- ตรวจสอบการตอบกลับของบริการ
    หากบริการยอมรับข้อมูลเข้าสู่ระบบ โปรแกรมตรวจสอบสิทธิ์จะ
    จัดเก็บข้อมูลเข้าสู่ระบบไว้ใช้ในภายหลังได้ เนื่องจากเฟรมเวิร์กของโปรแกรมตรวจสอบสิทธิ์แบบปลั๊กอิน
    AccountManager จึงสามารถให้สิทธิ์เข้าถึงโทเค็นการตรวจสอบสิทธิ์ที่โปรแกรมตรวจสอบสิทธิ์
    รองรับและเลือกที่จะเปิดเผย เช่น โทเค็นการตรวจสอบสิทธิ์ OAuth2
แม้ว่าจะไม่จำเป็นต้องมีการตรวจสอบสิทธิ์ แต่บริการรายชื่อติดต่อส่วนใหญ่ก็ใช้การตรวจสอบสิทธิ์ อย่างไรก็ตาม คุณไม่จำเป็นต้องใช้เฟรมเวิร์กการตรวจสอบสิทธิ์ของ Android เพื่อทำการตรวจสอบสิทธิ์
การติดตั้งใช้งานอะแดปเตอร์การซิงค์
หากต้องการใช้ตัวดัดแปลงการซิงค์สำหรับผู้ให้บริการรายชื่อติดต่อ คุณต้องเริ่มต้นด้วยการสร้างแอปพลิเคชัน Android ที่มีสิ่งต่อไปนี้
- 
            คอมโพเนนต์ Serviceที่ตอบสนองต่อคำขอจากระบบเพื่อ เชื่อมโยงกับ Sync Adapter
- 
            เมื่อระบบต้องการเรียกใช้การซิงค์ ระบบจะเรียกใช้เมธอด onBind()ของบริการเพื่อรับIBinderสำหรับ Sync Adapter ซึ่งช่วยให้ระบบ โทรข้ามกระบวนการไปยังเมธอดของอแดปเตอร์ได้
- 
            อะแดปเตอร์การซิงค์จริงที่ใช้เป็นคลาสย่อยที่เฉพาะเจาะจงของ
            AbstractThreadedSyncAdapter
- 
            คลาสนี้จะทำหน้าที่ดาวน์โหลดข้อมูลจากเซิร์ฟเวอร์ อัปโหลดข้อมูลจาก
            อุปกรณ์ และแก้ไขข้อขัดแย้ง การทำงานหลักของอแดปเตอร์จะ
            ดำเนินการในเมธอด onPerformSync()ต้องสร้างอินสแตนซ์ของคลาสนี้เป็น Singleton
- 
            คลาสย่อยของ Application
- 
            คลาสนี้ทำหน้าที่เป็นโรงงานสำหรับซิงค์อะแดปเตอร์แบบ Singleton ใช้วิธี onCreate()เพื่อสร้างอินสแตนซ์ของ SyncAdapter และ ระบุเมธอด "getter" แบบคงที่เพื่อส่งคืน Singleton ไปยัง เมธอดonBind()ของบริการ SyncAdapter
- 
            ไม่บังคับ: Serviceคอมโพเนนต์ที่ตอบกลับ คำขอจากระบบสำหรับการตรวจสอบสิทธิ์ผู้ใช้
- 
            AccountManagerเริ่มบริการนี้เพื่อเริ่มกระบวนการ ตรวจสอบสิทธิ์ เมธอดonCreate()ของบริการจะสร้างออบเจ็กต์ เครื่องมือตรวจสอบสิทธิ์ เมื่อระบบต้องการตรวจสอบสิทธิ์บัญชีผู้ใช้สำหรับ Sync Adapter ของแอปพลิเคชัน ระบบจะเรียกใช้เมธอดonBind()ของบริการเพื่อรับIBinderสำหรับเครื่องมือตรวจสอบสิทธิ์ ซึ่งจะช่วยให้ระบบ โทรข้ามกระบวนการไปยังเมธอดของเครื่องมือตรวจสอบสิทธิ์ได้
- 
            ไม่บังคับ: คลาสย่อยที่เฉพาะเจาะจงของ
            AbstractAccountAuthenticatorซึ่งจัดการคำขอสำหรับ การตรวจสอบสิทธิ์
- 
            คลาสนี้มีเมธอดที่ AccountManagerเรียกใช้ เพื่อตรวจสอบสิทธิ์ข้อมูลเข้าสู่ระบบของผู้ใช้กับเซิร์ฟเวอร์ รายละเอียดของ กระบวนการตรวจสอบสิทธิ์จะแตกต่างกันไปตามเทคโนโลยีเซิร์ฟเวอร์ที่ใช้ คุณควร ดูเอกสารประกอบสำหรับซอฟต์แวร์เซิร์ฟเวอร์เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับการตรวจสอบสิทธิ์
- ไฟล์ XML ที่กำหนด Sync Adapter และเครื่องมือตรวจสอบสิทธิ์ให้กับระบบ
- 
            คอมโพเนนต์บริการตัวตรวจสอบสิทธิ์และตัวปรับการซิงค์ที่อธิบายไว้ก่อนหน้านี้จะ
            กำหนดไว้ใน
<service>ในไฟล์ Manifest ของแอปพลิเคชัน องค์ประกอบเหล่านี้ มีองค์ประกอบย่อย<meta-data>ซึ่งให้ข้อมูลที่เฉพาะเจาะจงแก่ระบบ- 
                    องค์ประกอบ
<meta-data>สำหรับบริการอะแดปเตอร์การซิงค์จะชี้ไปยัง ไฟล์ XMLres/xml/syncadapter.xmlในทางกลับกัน ไฟล์นี้จะระบุ URI สำหรับเว็บเซอร์วิสที่จะซิงค์กับผู้ให้บริการรายชื่อติดต่อ และประเภทบัญชีสำหรับเว็บเซอร์วิส
- 
                    ไม่บังคับ: องค์ประกอบ
<meta-data>สำหรับโปรแกรมตรวจสอบสิทธิ์จะชี้ไปยังไฟล์ XMLres/xml/authenticator.xmlในทางกลับกัน ไฟล์นี้จะระบุ ประเภทบัญชีที่เครื่องมือตรวจสอบสิทธิ์นี้รองรับ รวมถึงทรัพยากร UI ที่ ปรากฏในระหว่างกระบวนการตรวจสอบสิทธิ์ ประเภทบัญชีที่ระบุในองค์ประกอบนี้ต้องเหมือนกับประเภทบัญชีที่ระบุสำหรับอะแดปเตอร์การซิงค์
 
- 
                    องค์ประกอบ
ข้อมูลสตรีมโซเชียล
ตาราง android.provider.ContactsContract.StreamItems และ android.provider.ContactsContract.StreamItemPhotos จัดการข้อมูลขาเข้าจากโซเชียลเน็ตเวิร์ก คุณเขียนตัวดัดแปลงการซิงค์ที่เพิ่มข้อมูลสตรีม จากเครือข่ายของคุณเองลงในตารางเหล่านี้ หรือจะอ่านข้อมูลสตรีมจากตารางเหล่านี้และ แสดงในแอปพลิเคชันของคุณเอง หรือทั้ง 2 อย่างก็ได้ ฟีเจอร์เหล่านี้ช่วยให้คุณผสานรวมบริการและแอปพลิเคชันเครือข่ายสังคม เข้ากับประสบการณ์การใช้งานเครือข่ายสังคมของ 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
- สตริงข้อความที่มีเวลาที่แทรกหรืออัปเดตรายการสตรีมในรูปแบบมิลลิวินาทีตั้งแต่ Epoch แอปพลิเคชันที่แทรกหรืออัปเดตรายการสตรีมมี หน้าที่ดูแลคอลัมน์นี้ โดย Contacts Provider จะไม่ดูแลคอลัมน์นี้โดยอัตโนมัติ
หากต้องการแสดงข้อมูลระบุสำหรับรายการสตรีม ให้ใช้ 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 สำหรับใช้กับ Sync Adapter เท่านั้น
รูปภาพในสตรีมโซเชียล
   ตาราง android.provider.ContactsContract.StreamItemPhotos จะจัดเก็บรูปภาพที่เชื่อมโยง
   กับรายการสตรีม คอลัมน์ android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID ของตาราง
   ลิงก์ไปยังค่าในคอลัมน์ _ID ของ
   ตาราง android.provider.ContactsContract.StreamItems ระบบจะจัดเก็บข้อมูลอ้างอิงรูปภาพไว้ในตาราง
   ในคอลัมน์ต่อไปนี้
- คอลัมน์ android.provider.ContactsContract.StreamItemPhotos#PHOTO (BLOB)
- การแสดงรูปภาพในรูปแบบไบนารี ซึ่งผู้ให้บริการปรับขนาดเพื่อจัดเก็บและแสดง คอลัมน์นี้พร้อมใช้งานเพื่อให้เข้ากันได้แบบย้อนหลังกับ Contacts Provider เวอร์ชันก่อนหน้าซึ่งใช้คอลัมน์นี้ในการจัดเก็บรูปภาพ อย่างไรก็ตาม ในเวอร์ชันปัจจุบัน คุณไม่ควรใช้คอลัมน์นี้เพื่อจัดเก็บรูปภาพ แต่ให้ใช้ android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID หรือ android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI (ทั้ง 2 รายการ อธิบายไว้ในจุดต่อไปนี้) เพื่อจัดเก็บรูปภาพในไฟล์แทน ตอนนี้คอลัมน์นี้ มีภาพขนาดย่อของรูปภาพซึ่งพร้อมให้อ่านแล้ว
- android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID
- 
        ตัวระบุตัวเลขของรูปภาพสำหรับรายชื่อติดต่อดิบ ผนวกค่านี้เข้ากับค่าคงที่
        DisplayPhoto.CONTENT_URIเพื่อรับ URI เนื้อหาที่ชี้ไปยังไฟล์รูปภาพเดียว แล้วเรียกใช้openAssetFileDescriptor()เพื่อรับแฮนเดิลไปยังไฟล์รูปภาพ
- android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI
- 
        URI ของเนื้อหาที่ชี้ไปยังไฟล์รูปภาพโดยตรงสำหรับรูปภาพที่แถวนี้แสดง
        โทรหา openAssetFileDescriptor()ด้วย URI นี้เพื่อรับแฮนเดิลไปยังไฟล์รูปภาพ
การใช้ตารางสตรีมโซเชียล
ตารางเหล่านี้ทำงานเหมือนกับตารางหลักอื่นๆ ใน Contacts Provider ยกเว้นว่า
- ตารางเหล่านี้ต้องมีสิทธิ์เข้าถึงเพิ่มเติม หากต้องการอ่านข้อมูลจากสตรีมเหล่านั้น แอปพลิเคชันของคุณ ต้องมีสิทธิ์ 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 ซึ่งมีแถวรูปภาพสำหรับรายการสตรีมรายการเดียว
การโต้ตอบในสตรีมโซเชียล
ข้อมูลสตรีมโซเชียลที่จัดการโดยผู้ให้บริการรายชื่อติดต่อร่วมกับแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์เป็นวิธีที่มีประสิทธิภาพในการเชื่อมต่อระบบเครือข่ายโซเชียลกับรายชื่อติดต่อที่มีอยู่ ฟีเจอร์ต่อไปนี้พร้อมใช้งาน
- การซิงค์บริการเครือข่ายสังคมกับผู้ให้บริการรายชื่อติดต่อด้วยอะแดปเตอร์ sync จะช่วยให้คุณดึงกิจกรรมล่าสุดของรายชื่อติดต่อของผู้ใช้และจัดเก็บไว้ในตาราง android.provider.ContactsContract.StreamItems และ android.provider.ContactsContract.StreamItemPhotos เพื่อใช้ในภายหลังได้
- นอกจากการซิงค์ปกติแล้ว คุณยังเรียกใช้ตัวดัดแปลงการซิงค์เพื่อดึงข้อมูลเพิ่มเติมได้เมื่อผู้ใช้เลือกรายชื่อติดต่อเพื่อดู ซึ่งจะช่วยให้ตัวดัดแปลงการซิงค์ ดึงรูปภาพความละเอียดสูงและรายการสตรีมล่าสุดสำหรับรายชื่อติดต่อได้
- การลงทะเบียนการแจ้งเตือนกับแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์และ Contacts Provider จะช่วยให้คุณรับ Intent เมื่อมีการดูรายชื่อติดต่อ และอัปเดตสถานะของรายชื่อติดต่อจากบริการของคุณได้ในเวลานั้น วิธีนี้อาจเร็วกว่าและใช้แบนด์วิดท์น้อยกว่าการซิงค์แบบเต็มด้วยอะแดปเตอร์การซิงค์
- ผู้ใช้สามารถเพิ่มรายชื่อติดต่อลงในบริการเครือข่ายสังคมออนไลน์ขณะดูรายชื่อติดต่อ ในแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ คุณเปิดใช้ฟีเจอร์นี้ได้ด้วยฟีเจอร์ "เชิญรายชื่อติดต่อ" ซึ่งคุณเปิดใช้ได้ด้วยการรวมกิจกรรมที่เพิ่มรายชื่อติดต่อที่มีอยู่ลงใน เครือข่ายของคุณ และไฟล์ XML ที่ให้รายละเอียดแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์และ ผู้ให้บริการรายชื่อติดต่อพร้อมรายละเอียดของแอปพลิเคชันของคุณ
การซิงค์รายการในสตรีมกับผู้ให้บริการรายชื่อติดต่อเป็นประจำจะเหมือนกับการซิงค์อื่นๆ ดูข้อมูลเพิ่มเติมเกี่ยวกับการซิงค์ได้ที่ส่วน อะแดปเตอร์การซิงค์ของผู้ให้บริการรายชื่อติดต่อ การลงทะเบียนการแจ้งเตือนและ การเชิญผู้ติดต่อจะกล่าวถึงใน 2 ส่วนถัดไป
การลงทะเบียนเพื่อจัดการมุมมองของโซเชียลเน็ตเวิร์ก
หากต้องการลงทะเบียน Sync Adapter เพื่อรับการแจ้งเตือนเมื่อผู้ใช้ดูรายชื่อติดต่อที่ Sync Adapter ของคุณจัดการ ให้ทำดังนี้
- 
        สร้างไฟล์ชื่อ contacts.xmlในไดเรกทอรีres/xml/ของโปรเจ็กต์ หากมีไฟล์นี้อยู่แล้ว ให้ข้ามขั้นตอนนี้
- 
        ในไฟล์นี้ ให้เพิ่มองค์ประกอบ
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">หากมีองค์ประกอบนี้อยู่แล้ว ให้ข้ามขั้นตอนนี้
- 
        หากต้องการลงทะเบียนบริการที่จะได้รับการแจ้งเตือนเมื่อผู้ใช้เปิดหน้ารายละเอียดของรายชื่อติดต่อใน
        แอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ ให้เพิ่มแอตทริบิวต์
        viewContactNotifyService="serviceclass"ลงในองค์ประกอบ โดยที่serviceclassคือชื่อคลาสที่มีคุณสมบัติครบถ้วนของบริการ ที่ควรได้รับ Intent จากแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ สำหรับบริการแจ้งเตือน ให้ใช้คลาสที่ขยายIntentServiceเพื่อให้บริการรับ Intent ได้ ข้อมูลใน Intent ขาเข้ามี URI เนื้อหาของรายชื่อติดต่อดิบที่ผู้ใช้คลิก จากบริการแจ้งเตือน คุณสามารถเชื่อมโยงและเรียกใช้ Sync Adapter เพื่ออัปเดตข้อมูลสำหรับรายชื่อติดต่อดิบ
หากต้องการลงทะเบียนกิจกรรมที่จะเรียกใช้เมื่อผู้ใช้คลิกรายการในสตรีม รูปภาพ หรือทั้ง 2 อย่าง ให้ทำดังนี้
- 
        สร้างไฟล์ชื่อ contacts.xmlในไดเรกทอรีres/xml/ของโปรเจ็กต์ หากมีไฟล์นี้อยู่แล้ว ให้ข้ามขั้นตอนนี้
- 
        ในไฟล์นี้ ให้เพิ่มองค์ประกอบ
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">หากมีองค์ประกอบนี้อยู่แล้ว ให้ข้ามขั้นตอนนี้
- 
        หากต้องการลงทะเบียนกิจกรรมอย่างใดอย่างหนึ่งเพื่อจัดการเมื่อผู้ใช้คลิกรายการในสตรีมในแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ ให้เพิ่มแอตทริบิวต์
        viewStreamItemActivity="activityclass"ลงในองค์ประกอบ โดยที่activityclassคือชื่อคลาสแบบเต็มของกิจกรรม ที่ควรรับ Intent จากแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์
- 
        หากต้องการลงทะเบียนกิจกรรมอย่างใดอย่างหนึ่งเพื่อจัดการเมื่อผู้ใช้คลิกรูปภาพในสตรีมในแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ ให้เพิ่มแอตทริบิวต์
        viewStreamItemPhotoActivity="activityclass"ลงในองค์ประกอบ โดยที่activityclassคือชื่อคลาสแบบเต็มของกิจกรรม ที่ควรรับ Intent จากแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์
    องค์ประกอบ <ContactsAccountType> มีคำอธิบายโดยละเอียดในส่วนองค์ประกอบ<ContactsAccountType>
Intent ขาเข้ามี URI เนื้อหาของรายการหรือรูปภาพที่ผู้ใช้คลิก หากต้องการมีกิจกรรมแยกกันสำหรับรายการข้อความและรูปภาพ ให้ใช้ทั้ง 2 แอตทริบิวต์ในไฟล์เดียวกัน
การโต้ตอบกับบริการโซเชียลเน็ตเวิร์ก
ผู้ใช้ไม่จำเป็นต้องออกจากแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์เพื่อเชิญรายชื่อติดต่อไปยังเว็บไซต์เครือข่ายสังคม ของคุณ แต่คุณสามารถให้แอปรายชื่อติดต่อของอุปกรณ์ส่ง Intent เพื่อเชิญ รายชื่อติดต่อเข้าร่วมกิจกรรมใดกิจกรรมหนึ่งของคุณได้ โดยมีวิธีการตั้งค่าดังนี้
- 
        สร้างไฟล์ชื่อ contacts.xmlในไดเรกทอรีres/xml/ของโปรเจ็กต์ หากมีไฟล์นี้อยู่แล้ว ให้ข้ามขั้นตอนนี้
- 
        ในไฟล์นี้ ให้เพิ่มองค์ประกอบ
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">หากมีองค์ประกอบนี้อยู่แล้ว ให้ข้ามขั้นตอนนี้
- 
        เพิ่มแอตทริบิวต์ต่อไปนี้
        - inviteContactActivity="activityclass"
- 
                inviteContactActionLabel="@string/invite_action_label"
 activityclassคือชื่อคลาสแบบเต็มของ กิจกรรมที่ควรได้รับ Intentinvite_action_labelค่าคือสตริงข้อความที่แสดงในเมนูเพิ่มการเชื่อมต่อในแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์
    หมายเหตุ: ContactsSource เป็นชื่อแท็กที่เลิกใช้งานแล้วสำหรับ
    ContactsAccountType
การอ้างอิง contacts.xml
    ไฟล์ contacts.xml มีองค์ประกอบ XML ที่ควบคุมการโต้ตอบของ
    Sync Adapter และแอปพลิเคชันกับแอปพลิเคชันรายชื่อติดต่อและผู้ให้บริการรายชื่อติดต่อ องค์ประกอบเหล่านี้มีคำอธิบายในส่วนต่อไปนี้
องค์ประกอบ <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>
Description:
ประกาศคอมโพเนนต์ Android และป้ายกำกับ UI ที่อนุญาตให้ผู้ใช้เชิญรายชื่อติดต่อรายใดรายหนึ่งไปยัง โซเชียลเน็ตเวิร์ก แจ้งเตือนผู้ใช้เมื่อสตรีมโซเชียลเน็ตเวิร์กรายการใดรายการหนึ่งมีการอัปเดต และ อื่นๆ
    โปรดทราบว่าไม่จำเป็นต้องมีคำนำหน้าแอตทริบิวต์ android: สำหรับแอตทริบิวต์
    ของ <ContactsAccountType>
แอตทริบิวต์
- inviteContactActivity
- ชื่อคลาสแบบเต็มของกิจกรรมในแอปพลิเคชันที่คุณต้องการ เปิดใช้งานเมื่อผู้ใช้เลือกเพิ่มการเชื่อมต่อจาก แอปพลิเคชันรายชื่อติดต่อของอุปกรณ์
- inviteContactActionLabel
- 
        สตริงข้อความที่แสดงสำหรับกิจกรรมที่ระบุใน
        inviteContactActivityในเมนูเพิ่มการเชื่อมต่อ เช่น คุณสามารถใช้สตริง "ติดตามในเครือข่ายของฉัน" คุณใช้ตัวระบุทรัพยากรสตริง สำหรับป้ายกำกับนี้ได้
- viewContactNotifyService
- ชื่อคลาสที่มีคุณสมบัติครบถ้วนของบริการในแอปพลิเคชันของคุณซึ่งควรได้รับการแจ้งเตือน เมื่อผู้ใช้ดูรายชื่อติดต่อ การแจ้งเตือนนี้ส่งโดยแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ ซึ่งจะช่วยให้แอปพลิเคชันของคุณเลื่อนการดำเนินการที่ใช้ข้อมูลจำนวนมากออกไปจนกว่าจะจำเป็นได้ ตัวอย่างเช่น แอปพลิเคชันของคุณสามารถตอบสนองต่อการแจ้งเตือนนี้ โดยการอ่านและแสดงรูปภาพความละเอียดสูงของรายชื่อติดต่อและรายการสตรีมโซเชียลล่าสุด ฟีเจอร์นี้อธิบายไว้โดยละเอียดในส่วนการโต้ตอบในสตรีมโซเชียล
- viewGroupActivity
- ชื่อคลาสแบบเต็มของกิจกรรมในแอปพลิเคชันที่แสดงข้อมูลกลุ่มได้ เมื่อผู้ใช้คลิกป้ายกำกับกลุ่มในแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ ระบบจะแสดง UI สำหรับกิจกรรมนี้
- viewGroupActionLabel
- 
        ป้ายกำกับที่แอปพลิเคชันรายชื่อติดต่อแสดงสำหรับตัวควบคุม UI ที่อนุญาต
        ให้ผู้ใช้ดูกลุ่มในแอปพลิเคชันของคุณ
        แอตทริบิวต์นี้อนุญาตให้ใช้ตัวระบุทรัพยากรสตริง 
- viewStreamItemActivity
- ชื่อคลาสแบบเต็มของกิจกรรมในแอปพลิเคชันที่แอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ จะเปิดขึ้นเมื่อผู้ใช้คลิกรายการสตรีมสำหรับรายชื่อติดต่อดิบ
- viewStreamItemPhotoActivity
- ชื่อคลาสแบบเต็มของกิจกรรมในแอปพลิเคชันที่แอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ จะเปิดขึ้นเมื่อผู้ใช้คลิกรูปภาพในรายการสตรีมสำหรับรายชื่อติดต่อดิบ
องค์ประกอบ <ContactsDataKind>
    องค์ประกอบ <ContactsDataKind> ควบคุมการแสดงแถวข้อมูลที่กำหนดเองของแอปพลิเคชันใน UI ของแอปพลิเคชันรายชื่อติดต่อ โดยมีไวยากรณ์ดังนี้
<ContactsDataKind android:mimeType="MIMEtype" android:icon="icon_resources" android:summaryColumn="column_name" android:detailColumn="column_name">
มีอยู่ใน:
<ContactsAccountType>
Description:
    ใช้องค์ประกอบนี้เพื่อให้แอปพลิเคชันรายชื่อติดต่อแสดงเนื้อหาของแถวข้อมูลที่กำหนดเองเป็น
    ส่วนหนึ่งของรายละเอียดของรายชื่อติดต่อดิบ <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
- ชื่อคอลัมน์สำหรับค่าแรกจาก 2 ค่าที่ดึงมาจากแถวข้อมูล ค่า จะแสดงเป็นบรรทัดแรกของรายการสำหรับแถวข้อมูลนี้ บรรทัดแรกมีไว้ เพื่อใช้เป็นข้อมูลสรุป แต่จะใช้หรือไม่ก็ได้ ดูเพิ่มเติม android:detailColumn
- android:detailColumn
- 
        ชื่อคอลัมน์สำหรับค่าที่ 2 จาก 2 ค่าที่ดึงมาจากแถวข้อมูล ค่าจะ
        แสดงเป็นบรรทัดที่ 2 ของรายการสำหรับแถวข้อมูลนี้ ดูเพิ่มเติม
        android:summaryColumn
ฟีเจอร์เพิ่มเติมของ Contacts Provider
นอกเหนือจากฟีเจอร์หลักที่อธิบายไว้ในส่วนก่อนหน้าแล้ว ผู้ให้บริการรายชื่อติดต่อยังมีฟีเจอร์ที่มีประโยชน์ต่อไปนี้สำหรับการทำงานกับข้อมูลรายชื่อติดต่อ
- กลุ่มรายชื่อติดต่อ
- ฟีเจอร์รูปภาพ
กลุ่มรายชื่อติดต่อ
    ผู้ให้บริการรายชื่อติดต่อจะติดป้ายกำกับคอลเล็กชันของรายชื่อติดต่อที่เกี่ยวข้องด้วยข้อมูลกลุ่มหรือไม่ก็ได้ หากเซิร์ฟเวอร์ที่เชื่อมโยงกับบัญชีผู้ใช้ต้องการดูแลรักษากลุ่ม อะแดปเตอร์การซิงค์สำหรับประเภทบัญชีของบัญชีควรโอนข้อมูลกลุ่มระหว่างผู้ให้บริการรายชื่อติดต่อกับเซิร์ฟเวอร์ เมื่อผู้ใช้เพิ่มรายชื่อติดต่อใหม่ลงในเซิร์ฟเวอร์
    แล้วใส่รายชื่อติดต่อนี้ในกลุ่มใหม่ ตัวดัดแปลงการซิงค์จะต้องเพิ่มกลุ่มใหม่
    ลงในตาราง ContactsContract.Groups ระบบจะจัดเก็บกลุ่มที่รายชื่อติดต่อดิบ
    เป็นสมาชิกไว้ในตาราง ContactsContract.Data โดยใช้
    ประเภท MIME ของ ContactsContract.CommonDataKinds.GroupMembership
    หากคุณกำลังออกแบบ Sync Adapter ที่จะเพิ่มข้อมูลรายชื่อติดต่อดิบจากเซิร์ฟเวอร์ไปยังผู้ให้บริการรายชื่อติดต่อ และไม่ได้ใช้กลุ่ม คุณจะต้องบอกให้ผู้ให้บริการแสดงข้อมูลของคุณ ในโค้ดที่เรียกใช้เมื่อผู้ใช้เพิ่มบัญชี
    ลงในอุปกรณ์ ให้อัปเดตแถว 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 ซึ่งมีคำอธิบายโดยละเอียดในส่วนรูปภาพในสตรีมโซเชียล
