Contacts Provider

Contacts Provider เป็นคอมโพเนนต์ Android ที่มีประสิทธิภาพและยืดหยุ่นซึ่งจัดการที่เก็บข้อมูลส่วนกลางของอุปกรณ์เกี่ยวกับผู้คน Contacts Provider คือแหล่งข้อมูล ที่คุณเห็นในแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ และคุณยังเข้าถึงข้อมูลใน แอปพลิเคชันของคุณเองและโอนข้อมูลระหว่างอุปกรณ์กับบริการออนไลน์ได้ด้วย ผู้ให้บริการรองรับ แหล่งข้อมูลที่หลากหลายและพยายามจัดการข้อมูลให้ได้มากที่สุดสำหรับแต่ละบุคคล ซึ่งส่งผลให้ องค์กรมีความซับซ้อน ด้วยเหตุนี้ API ของผู้ให้บริการจึงมีชุดคลาสและอินเทอร์เฟซของสัญญาที่ครอบคลุม ซึ่งช่วยให้ทั้งการดึงข้อมูลและการแก้ไขข้อมูลเป็นไปอย่างราบรื่น

คู่มือนี้อธิบายสิ่งต่อไปนี้

  • โครงสร้างพื้นฐานของผู้ให้บริการ
  • วิธีกู้คืนข้อมูลจากผู้ให้บริการ
  • วิธีแก้ไขข้อมูลในผู้ให้บริการ
  • วิธีเขียนอะแดปเตอร์การซิงค์สำหรับซิงค์ข้อมูลจากเซิร์ฟเวอร์ไปยัง Contacts Provider

คู่มือนี้ถือว่าคุณทราบข้อมูลพื้นฐานเกี่ยวกับผู้ให้บริการเนื้อหาของ Android ดูข้อมูลเพิ่มเติม เกี่ยวกับผู้ให้บริการเนื้อหาของ Android ได้ในคู่มือ พื้นฐานของผู้ให้บริการเนื้อหา

องค์กร Contacts Provider

Contacts Provider เป็นคอมโพเนนต์ผู้ให้บริการเนื้อหาของ Android โดยจะเก็บข้อมูล 3 ประเภทเกี่ยวกับบุคคล ซึ่งแต่ละประเภทจะสอดคล้องกับตารางที่ผู้ให้บริการเสนอ ดังที่แสดงในรูปที่ 1

รูปที่ 1 โครงสร้างตาราง Contacts Provider

โดยทั่วไปแล้วตารางทั้ง 3 จะอ้างอิงตามชื่อของคลาสสัญญา คลาส กำหนดค่าคงที่สำหรับ URI ของเนื้อหา ชื่อคอลัมน์ และค่าคอลัมน์ที่ใช้โดยตารางต่อไปนี้

ContactsContract.Contacts ตาราง
แถวที่แสดงถึงบุคคลต่างๆ โดยอิงตามการรวบรวมข้อมูลติดต่อดิบ
ContactsContract.RawContacts ตาราง
แถวที่มีข้อมูลสรุปของบุคคล ซึ่งเฉพาะเจาะจงสำหรับบัญชีและประเภทผู้ใช้
ContactsContract.Data ตาราง
แถวที่มีรายละเอียดสำหรับข้อมูลติดต่อดิบ เช่น อีเมลหรือหมายเลขโทรศัพท์

ตารางอื่นๆ ที่แสดงโดยคลาส Contract ใน ContactsContract คือตารางเสริมที่ Contacts Provider ใช้เพื่อจัดการการดำเนินการหรือรองรับ ฟังก์ชันเฉพาะในแอปพลิเคชันรายชื่อติดต่อหรือโทรศัพท์ของอุปกรณ์

ข้อมูลติดต่อดิบ

ข้อมูลติดต่อดิบแสดงข้อมูลของบุคคลที่มาจากประเภทบัญชีและชื่อบัญชีเดียว เนื่องจาก Contacts Provider อนุญาตให้ใช้บริการออนไลน์มากกว่า 1 รายการเป็นแหล่งข้อมูลของบุคคลหนึ่งๆ Contacts Provider จึงอนุญาตให้ใช้ข้อมูลติดต่อดิบหลายรายการสำหรับบุคคลเดียวกัน นอกจากนี้ ข้อมูลติดต่อดิบหลายรายการยังช่วยให้ผู้ใช้รวมข้อมูลของบุคคลจากบัญชีมากกว่า 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 ระบุประเภทบัญชีของคุณเสมอ ด้วยตัวระบุโดเมนสำหรับโดเมนที่คุณเป็นเจ้าของหรือควบคุม ซึ่งจะช่วยให้มั่นใจได้ว่า ประเภทบัญชีของคุณจะไม่ซ้ำกับใคร บัญชีประเภทที่มีข้อมูลรายชื่อติดต่อมักจะมีอะแดปเตอร์การซิงค์ที่เชื่อมโยงกันซึ่งจะ ซิงค์กับ Contacts Provider
DELETED แฟล็ก "deleted" สำหรับข้อมูลติดต่อดิบ แฟล็กนี้ช่วยให้ Contacts Provider สามารถเก็บแถวไว้ภายในจนกว่าอะแดปเตอร์การซิงค์ จะลบแถวออกจากเซิร์ฟเวอร์ของตนได้ แล้วจึงลบแถวออกจากที่เก็บ ในที่สุด

หมายเหตุ

หมายเหตุสำคัญเกี่ยวกับตาราง ContactsContract.RawContacts มีดังนี้

  • ระบบจะไม่จัดเก็บชื่อของรายชื่อติดต่อดิบในแถวของรายชื่อติดต่อดิบใน ContactsContract.RawContacts แต่จะจัดเก็บไว้ใน ตาราง ContactsContract.Data ใน แถว ContactsContract.CommonDataKinds.StructuredName ข้อมูลติดต่อดิบ มีแถวประเภทนี้เพียงแถวเดียวในตาราง ContactsContract.Data
  • ข้อควรระวัง: หากต้องการใช้ข้อมูลบัญชีของคุณเองในแถวข้อมูลติดต่อดิบ คุณต้อง ลงทะเบียนกับ AccountManager ก่อน โดยให้แจ้ง ให้ผู้ใช้เพิ่มประเภทบัญชีและชื่อบัญชีของตนลงในรายการบัญชี หากคุณไม่ ดำเนินการนี้ Contacts Provider จะลบแถวข้อมูลติดต่อดิบโดยอัตโนมัติ

    เช่น หากต้องการให้แอปเก็บรักษาข้อมูลรายชื่อติดต่อสำหรับบริการบนเว็บที่มีโดเมน 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 รายการจากงานนี้

  1. ข้อมูลติดต่อดิบสำหรับ "Thomas Higginson" ที่เชื่อมโยงกับ emily.dickinson@gmail.com ประเภทบัญชีผู้ใช้คือ Google
  2. ข้อมูลติดต่อดิบที่ 2 สำหรับ "Thomas Higginson" ที่เชื่อมโยงกับ emilyd@gmail.com ประเภทบัญชีผู้ใช้คือ Google มีข้อมูลติดต่อดิบที่ 2 แม้ว่าชื่อจะเหมือนกับชื่อก่อนหน้า เนื่องจากมีการเพิ่มบุคคลดังกล่าวสำหรับบัญชีผู้ใช้ที่แตกต่างกัน
  3. ข้อมูลติดต่อดิบที่ 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 Contacts Provider จะจัดเก็บแถวอีเมล 2 แถว และลิงก์ทั้ง 2 แถวกับข้อมูลติดต่อดิบ

โปรดทราบว่าข้อมูลประเภทต่างๆ จะจัดเก็บไว้ในตารางเดียวนี้ แถวชื่อที่แสดง หมายเลขโทรศัพท์ อีเมล ที่อยู่ทางไปรษณีย์ รูปภาพ และรายละเอียดเว็บไซต์ทั้งหมดจะอยู่ในตาราง ContactsContract.Data ตาราง ContactsContract.Data มีคอลัมน์บางรายการที่มีชื่อที่สื่อความหมาย และคอลัมน์อื่นๆ ที่มีชื่อทั่วไป เพื่อช่วยในการจัดการ เนื้อหาของคอลัมน์ชื่อที่สื่อความหมายจะมีค่าเหมือนกัน ไม่ว่าจะเป็นข้อมูลประเภทใดในแถว ในขณะที่เนื้อหาของคอลัมน์ชื่อทั่วไปจะมี ค่าแตกต่างกันไปตามประเภทข้อมูล

ชื่อคอลัมน์ที่สื่อความหมาย

ตัวอย่างชื่อคอลัมน์ที่สื่อความหมายมีดังนี้

RAW_CONTACT_ID
ค่าของคอลัมน์ _ID ของข้อมูลติดต่อดิบสำหรับข้อมูลนี้
MIMETYPE
ประเภทข้อมูลที่จัดเก็บในแถวนี้ ซึ่งแสดงเป็นประเภท MIME ที่กำหนดเอง Contacts Provider ใช้ประเภท MIME ที่กำหนดไว้ในคลาสย่อยของ ContactsContract.CommonDataKinds MIME ประเภทเหล่านี้เป็นโอเพนซอร์ส และแอปพลิเคชันหรืออะแดปเตอร์การซิงค์ใดก็ได้ที่ใช้ได้กับ Contacts Provider จะใช้ MIME ประเภทเหล่านี้ได้
IS_PRIMARY
หากแถวข้อมูลประเภทนี้เกิดขึ้นได้มากกว่า 1 ครั้งสำหรับข้อมูลติดต่อดิบ คอลัมน์IS_PRIMARYจะ ติดค่าสถานะแถวข้อมูลที่มีข้อมูลหลักสำหรับประเภทนั้น เช่น หาก ผู้ใช้กดหมายเลขโทรศัพท์ของรายชื่อติดต่อค้างไว้แล้วเลือกตั้งค่าเริ่มต้น แถว ContactsContract.Data ที่มีหมายเลขนั้น จะมีคอลัมน์ IS_PRIMARY ที่ตั้งค่าเป็น ค่าที่ไม่ใช่ 0

ชื่อคอลัมน์ทั่วไป

มีคอลัมน์ทั่วไป 15 รายการชื่อ DATA1 ถึง DATA15 ซึ่งพร้อมให้บริการโดยทั่วไป และคอลัมน์ทั่วไปอีก 4 รายการ SYNC1 ถึง SYNC4 ซึ่งควรใช้โดยอะแดปเตอร์การซิงค์เท่านั้น ค่าคงที่ชื่อคอลัมน์ทั่วไปจะใช้งานได้เสมอ ไม่ว่าแถวจะมีข้อมูลประเภทใดก็ตาม

คอลัมน์ DATA1 มีการจัดทำดัชนี Contacts Provider จะใช้คอลัมน์นี้เสมอสำหรับ ข้อมูลที่ผู้ให้บริการคาดว่าจะเป็นเป้าหมายของการค้นหาที่พบบ่อยที่สุด เช่น ในแถวอีเมล คอลัมน์นี้จะมีอีเมลจริง

ตามธรรมเนียมแล้ว คอลัมน์ DATA15 จะสงวนไว้สำหรับจัดเก็บข้อมูล Binary Large Object (BLOB) เช่น รูปขนาดย่อของรูปภาพ

ชื่อคอลัมน์เฉพาะประเภท

เพื่ออำนวยความสะดวกในการทำงานกับคอลัมน์สำหรับแถวประเภทใดประเภทหนึ่ง Contacts Provider ยังมีค่าคงที่ชื่อคอลัมน์ที่เฉพาะเจาะจงประเภท ซึ่งกำหนดไว้ในคลาสย่อยของ 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 กลุ่มเป็นฟีเจอร์ที่ไม่บังคับของประเภทบัญชีและชื่อบัญชี ซึ่งอธิบายไว้อย่างละเอียดในส่วนกลุ่มรายชื่อติดต่อ

รายชื่อติดต่อ

Contacts Provider จะรวมแถวข้อมูลติดต่อดิบในบัญชีทุกประเภทและชื่อบัญชี เพื่อสร้างรายชื่อติดต่อ ซึ่งช่วยให้แสดงและแก้ไขข้อมูลทั้งหมดที่ผู้ใช้รวบรวมไว้สำหรับบุคคลหนึ่งๆ ได้ง่ายขึ้น Contacts Provider จะจัดการการสร้างแถวรายชื่อติดต่อใหม่ และการรวมข้อมูลรายชื่อติดต่อดิบกับแถวรายชื่อติดต่อที่มีอยู่ ไม่อนุญาตให้ทั้งแอปพลิเคชันและ ตัวปรับการซิงค์เพิ่มรายชื่อติดต่อ และคอลัมน์บางรายการในแถวรายชื่อติดต่อเป็นแบบอ่านอย่างเดียว

หมายเหตุ: หากพยายามเพิ่มรายชื่อติดต่อลงใน Contacts Provider ด้วย insert() คุณจะได้รับข้อยกเว้น UnsupportedOperationException หากคุณพยายามอัปเดตคอลัมน์ ที่แสดงเป็น "อ่านอย่างเดียว" ระบบจะไม่สนใจการอัปเดต

Contacts Provider จะสร้างรายชื่อติดต่อใหม่เพื่อตอบสนองต่อการเพิ่มข้อมูลติดต่อดิบใหม่ ซึ่งไม่ตรงกับรายชื่อติดต่อที่มีอยู่ ผู้ให้บริการจะดำเนินการนี้ด้วยหากข้อมูลของรายชื่อติดต่อเดิมมีการเปลี่ยนแปลงในลักษณะที่ข้อมูลไม่ตรงกับรายชื่อติดต่อที่เคยแนบไว้ หากแอปพลิเคชันหรืออะแดปเตอร์การซิงค์สร้างข้อมูลติดต่อดิบใหม่ที่ ตรงกับรายชื่อติดต่อที่มีอยู่ ระบบจะรวมข้อมูลติดต่อดิบใหม่กับรายชื่อติดต่อที่มีอยู่

Contacts Provider จะลิงก์แถวรายชื่อติดต่อกับแถวข้อมูลติดต่อดิบด้วยคอลัมน์ _ID ในตาราง Contacts ของแถวรายชื่อติดต่อ คอลัมน์ CONTACT_ID ของตารางรายชื่อติดต่อดิบ ContactsContract.RawContacts มีค่า _ID สำหรับ แถวรายชื่อติดต่อที่เชื่อมโยงกับแถวรายชื่อติดต่อดิบแต่ละแถว

ContactsContract.Contacts ตารางยังมีคอลัมน์ LOOKUP_KEY ซึ่งเป็นลิงก์ "ถาวร" ไปยังแถวของรายชื่อติดต่อ เนื่องจาก Contacts Provider จะดูแลรายชื่อติดต่อโดยอัตโนมัติ จึงอาจเปลี่ยนค่า _ID ของแถวรายชื่อติดต่อ เพื่อตอบสนองต่อการรวมข้อมูลหรือการซิงค์ แม้จะเกิดกรณีนี้ขึ้น URI เนื้อหา CONTENT_LOOKUP_URI เมื่อรวมกับ LOOKUP_KEYของรายชื่อติดต่อจะยังคง ชี้ไปยังแถวของรายชื่อติดต่อ คุณจึงใช้ LOOKUP_KEY เพื่อรักษาลิงก์ไปยังรายชื่อติดต่อ "รายการโปรด" และอื่นๆ ได้ คอลัมน์นี้มีรูปแบบของตัวเองซึ่ง ไม่เกี่ยวข้องกับรูปแบบของคอลัมน์ _ID

รูปที่ 3 แสดงความสัมพันธ์ของตารางหลัก 3 ตาราง

ตารางหลักของผู้ให้บริการรายชื่อติดต่อ

รูปที่ 3 ความสัมพันธ์ของตารางรายชื่อติดต่อ รายชื่อติดต่อดิบ และรายละเอียด

ข้อควรระวัง: หากคุณเผยแพร่แอปไปยัง Google Play Store หรือหากแอปอยู่ในอุปกรณ์ที่ใช้ Android 10 (ระดับ API 29) ขึ้นไป โปรดทราบว่าฟิลด์และวิธีการชุดข้อมูลรายชื่อติดต่อแบบจำกัดจะเลิกใช้งานแล้ว

ภายใต้เงื่อนไขที่กล่าวถึง ระบบจะล้างค่าที่เขียนลงในช่องข้อมูลต่อไปนี้เป็นระยะๆ

API ที่ใช้ในการตั้งค่าช่องข้อมูลข้างต้นจะเลิกใช้งานด้วยเช่นกัน

นอกจากนี้ ฟิลด์ต่อไปนี้จะไม่แสดงรายชื่อติดต่อที่ติดต่อบ่อยอีกต่อไป โปรดทราบ ว่าฟิลด์บางรายการเหล่านี้จะมีผลต่อการจัดอันดับรายชื่อติดต่อก็ต่อเมื่อรายชื่อติดต่อ เป็นส่วนหนึ่งของข้อมูล ประเภทที่เฉพาะเจาะจง

หากแอปของคุณเข้าถึงหรืออัปเดตฟิลด์หรือ 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 บริการเว็บที่อะแดปเตอร์การซิงค์ทำงานด้วยจะระบุตามประเภทบัญชี อะแดปเตอร์การซิงค์แต่ละตัวจะทำงานกับบัญชีประเภทเดียว แต่รองรับชื่อบัญชีหลายชื่อสำหรับประเภทนั้นได้ ประเภทบัญชีและชื่อบัญชีอธิบายไว้สั้นๆ ในส่วน แหล่งที่มาของข้อมูลรายชื่อติดต่อดิบ คำจำกัดความต่อไปนี้จะให้รายละเอียดเพิ่มเติม และอธิบายว่าประเภทบัญชีและชื่อเกี่ยวข้องกับอะแดปเตอร์การซิงค์และบริการอย่างไร

ประเภทบัญชี
ระบุบริการที่ผู้ใช้จัดเก็บข้อมูลไว้ โดยส่วนใหญ่แล้ว ผู้ใช้จะต้อง ตรวจสอบสิทธิ์กับบริการ เช่น Google Contacts เป็นประเภทบัญชีที่ระบุด้วยรหัส google.com ค่านี้สอดคล้องกับประเภทบัญชีที่ใช้โดย AccountManager
ชื่อบัญชี
ระบุบัญชีหรือการเข้าสู่ระบบที่เฉพาะเจาะจงสำหรับประเภทบัญชี บัญชี Google Contacts เหมือนกับบัญชี Google ซึ่งมีอีเมลเป็นชื่อบัญชี บริการอื่นๆ อาจใช้ชื่อผู้ใช้แบบคำเดียวหรือรหัสตัวเลข

ประเภทบัญชีไม่จำเป็นต้องไม่ซ้ำกัน ผู้ใช้สามารถกำหนดค่าบัญชี Google Contacts หลายบัญชี และดาวน์โหลดข้อมูลไปยัง Contacts Provider ได้ ซึ่งอาจเกิดขึ้นหากผู้ใช้มีรายชื่อติดต่อส่วนตัวชุดหนึ่ง สำหรับชื่อบัญชีส่วนตัว และอีกชุดหนึ่งสำหรับงาน ชื่อบัญชีมักจะไม่ซ้ำกัน โดยทั้ง 2 อย่างนี้จะระบุโฟลว์ข้อมูลที่เฉพาะเจาะจงระหว่าง Contacts Provider กับ บริการภายนอก

หากต้องการโอนข้อมูลของบริการไปยัง Contacts Provider คุณต้องเขียน อะแดปเตอร์การซิงค์ ของคุณเอง ซึ่งอธิบายไว้อย่างละเอียดในส่วน Contacts Provider sync adapters

รูปที่ 4 แสดงให้เห็นว่า Contacts Provider อยู่ในขั้นตอนการไหลของข้อมูล เกี่ยวกับผู้คนอย่างไร ในช่องที่มีเครื่องหมาย "sync adapters" อะแดปเตอร์แต่ละตัวจะมีป้ายกำกับตามประเภทบัญชี

โฟลว์ของข้อมูลเกี่ยวกับผู้คน

รูปที่ 4 โฟลว์ข้อมูลของ Contacts Provider

สิทธิ์ที่จำเป็น

แอปพลิเคชันที่ต้องการเข้าถึง 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

Contacts Provider จัดการข้อมูลที่ติดตามสถานะของข้อมูลรายชื่อติดต่อใน ที่เก็บ ระบบจะจัดเก็บข้อมูลเมตานี้เกี่ยวกับที่เก็บไว้ในที่ต่างๆ ซึ่งรวมถึงแถวตาราง Raw Contacts, Data และ Contacts, ตาราง ContactsContract.Settings และตาราง ContactsContract.SyncState ตารางต่อไปนี้แสดงผลของข้อมูลเมตาแต่ละรายการ

ตารางที่ 3 ข้อมูลเมตาใน Contacts Provider

โต๊ะ คอลัมน์ ค่า ความหมาย
ContactsContract.RawContacts DIRTY "0" - ไม่มีการเปลี่ยนแปลงนับตั้งแต่ซิงค์ครั้งล่าสุด ทำเครื่องหมายรายชื่อติดต่อดิบที่มีการเปลี่ยนแปลงในอุปกรณ์และต้องซิงค์กลับไปยังเซิร์ฟเวอร์ Contacts Provider จะตั้งค่าโดยอัตโนมัติเมื่อแอปพลิเคชัน Android อัปเดตแถว

อะแดปเตอร์การซิงค์ที่แก้ไขตารางข้อมูลหรือตารางข้อมูลติดต่อดิบควรต่อท้ายสตริง CALLER_IS_SYNCADAPTER กับ URI เนื้อหาที่ใช้เสมอ ซึ่งจะป้องกันไม่ให้ผู้ให้บริการทำเครื่องหมายแถวว่า "ไม่สะอาด" ไม่เช่นนั้น การแก้ไขอะแดปเตอร์การซิงค์จะปรากฏเป็นการแก้ไขในเครื่องและจะ ส่งไปยังเซิร์ฟเวอร์ แม้ว่าเซิร์ฟเวอร์จะเป็นแหล่งที่มาของการแก้ไขก็ตาม

"1" - มีการเปลี่ยนแปลงตั้งแต่การซิงค์ครั้งล่าสุด ต้องซิงค์กลับไปยังเซิร์ฟเวอร์
ContactsContract.RawContacts VERSION หมายเลขเวอร์ชันของแถวนี้ Contacts Provider จะเพิ่มค่านี้โดยอัตโนมัติเมื่อใดก็ตามที่แถวหรือ ข้อมูลที่เกี่ยวข้องมีการเปลี่ยนแปลง
ContactsContract.Data DATA_VERSION หมายเลขเวอร์ชันของแถวนี้ Contacts Provider จะเพิ่มค่านี้โดยอัตโนมัติทุกครั้งที่มีการเปลี่ยนแปลงแถวข้อมูล
ContactsContract.RawContacts SOURCE_ID ค่าสตริงที่ระบุข้อมูลติดต่อดิบนี้ในบัญชีที่สร้างขึ้นอย่างไม่ซ้ำกัน เมื่ออะแดปเตอร์การซิงค์สร้างข้อมูลติดต่อดิบใหม่ คอลัมน์นี้ควรตั้งค่าเป็นรหัสที่ไม่ซ้ำกันของเซิร์ฟเวอร์สำหรับข้อมูลติดต่อดิบ เมื่อแอปพลิเคชัน Android สร้าง ข้อมูลติดต่อดิบใหม่ แอปพลิเคชันควรปล่อยให้คอลัมน์นี้ว่างไว้ ซึ่งจะส่งสัญญาณไปยังอะแดปเตอร์การซิงค์ ว่าควรสร้างข้อมูลติดต่อดิบใหม่ในเซิร์ฟเวอร์ และรับค่าสำหรับ SOURCE_ID

โดยเฉพาะอย่างยิ่ง รหัสแหล่งที่มาต้องไม่ซ้ำกันสำหรับบัญชีแต่ละประเภท และควรคงที่ตลอดการซิงค์

  • ไม่ซ้ำกัน: ข้อมูลติดต่อดิบแต่ละรายการของบัญชีต้องมีรหัสแหล่งที่มาของตัวเอง หากคุณ ไม่บังคับใช้การตั้งค่านี้ จะทำให้เกิดปัญหาในแอปพลิเคชันรายชื่อผู้ติดต่อ โปรดทราบว่ารายชื่อติดต่อดิบ 2 รายการสำหรับบัญชีประเภทเดียวกันอาจมี รหัสแหล่งที่มาเดียวกัน เช่น ระบบอนุญาตให้ข้อมูลติดต่อดิบ "Thomas Higginson" สำหรับบัญชี emily.dickinson@gmail.com มีรหัสแหล่งที่มาเดียวกันกับข้อมูลติดต่อดิบ "Thomas Higginson" สำหรับบัญชี emilyd@gmail.com
  • เสถียร: รหัสแหล่งที่มาเป็นส่วนถาวรของข้อมูลบริการออนไลน์สำหรับ ข้อมูลติดต่อดิบ เช่น หากผู้ใช้ล้างที่เก็บข้อมูลรายชื่อติดต่อจากการ ตั้งค่าแอปและซิงค์อีกครั้ง รายชื่อติดต่อดิบที่กู้คืนควรมี รหัสแหล่งที่มาเหมือนเดิม หากไม่บังคับใช้ ทางลัดจะหยุดทำงาน
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

ส่วนนี้จะอธิบายหลักเกณฑ์ในการเข้าถึงข้อมูลจาก Contacts Provider โดยเน้นที่ หัวข้อต่อไปนี้

  • คำค้นหาเอนทิตี
  • การแก้ไขเป็นกลุ่ม
  • การดึงข้อมูลและการแก้ไขด้วย Intent
  • ความสมบูรณ์ของข้อมูล

การแก้ไขจากอะแดปเตอร์การซิงค์จะอธิบายรายละเอียดเพิ่มเติมในส่วน อะแดปเตอร์การซิงค์ของ 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 แต่ละแถว

เอนทิตีช่วยให้การค้นหาง่ายขึ้น การใช้เอนทิตีช่วยให้คุณดึงข้อมูลรายชื่อติดต่อทั้งหมดสำหรับ รายชื่อติดต่อหรือข้อมูลติดต่อดิบได้ในครั้งเดียว แทนที่จะต้องค้นหาตารางหลักก่อนเพื่อรับ รหัส แล้วจึงต้องค้นหาตารางรองด้วยรหัสนั้น นอกจากนี้ Contacts Provider ยังประมวลผล การค้นหาเทียบกับเอนทิตีในธุรกรรมเดียว ซึ่งช่วยให้มั่นใจว่าข้อมูลที่เรียก มาจะสอดคล้องกันภายใน

หมายเหตุ: โดยปกติแล้วเอนทิตีจะไม่มีคอลัมน์ทั้งหมดของตารางหลักและตารางย่อย หากพยายามใช้ชื่อคอลัมน์ที่ไม่ได้อยู่ในรายการค่าคงที่ของชื่อคอลัมน์ สำหรับเอนทิตี คุณจะได้รับ 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 นี้เพื่อแสดงหรือทำงานกับข้อมูลเพิ่มเติมได้

การแก้ไขแบบเป็นกลุ่ม

คุณควรแทรก อัปเดต และลบข้อมูลใน Contacts Provider ใน "โหมดกลุ่ม" โดยการสร้าง ArrayList ของออบเจ็กต์ ContentProviderOperation และเรียกใช้ applyBatch() ทุกครั้งที่ทำได้ เนื่องจาก Contacts Provider จะดำเนินการทั้งหมดใน applyBatch() ในธุรกรรมเดียว การแก้ไขของคุณจึงจะไม่ทำให้ที่เก็บรายชื่อติดต่ออยู่ในสถานะที่ไม่สอดคล้องกัน การแก้ไขแบบเป็นกลุ่มยังช่วยให้แทรกข้อมูลติดต่อดิบและข้อมูลรายละเอียดพร้อมกันได้ด้วย

หมายเหตุ: หากต้องการแก้ไขรายชื่อติดต่อดิบรายการเดียว ให้ลองส่ง Intent ไปยัง แอปพลิเคชันรายชื่อติดต่อของอุปกรณ์แทนที่จะจัดการการแก้ไขในแอป การดำเนินการนี้อธิบายไว้โดยละเอียดในส่วน การดึงข้อมูลและการแก้ไขด้วย Intent

จุดหยุดชั่วคราว

การแก้ไขแบบเป็นชุดที่มีการดำเนินการจำนวนมากอาจบล็อกกระบวนการอื่นๆ ซึ่งส่งผลให้ผู้ใช้ได้รับประสบการณ์การใช้งานโดยรวมที่ไม่ดี หากต้องการจัดระเบียบการแก้ไขทั้งหมดที่ต้องการ ดำเนินการในรายการแยกกันให้น้อยที่สุด และในขณะเดียวกันก็ป้องกันไม่ให้ การแก้ไขเหล่านั้นบล็อกระบบ คุณควรตั้งค่าคะแนนผลตอบแทนสำหรับการดำเนินการอย่างน้อย 1 รายการ จุดหยุดชั่วคราวคือออบเจ็กต์ ContentProviderOperation ที่มีค่า isYieldAllowed() ตั้งค่าเป็น true เมื่อ Contacts Provider พบจุดหยุดชั่วคราว ผู้ให้บริการจะหยุดการทำงานชั่วคราวเพื่อให้กระบวนการอื่นๆ ทำงานและปิดธุรกรรมปัจจุบัน เมื่อผู้ให้บริการเริ่มทำงานอีกครั้ง ผู้ให้บริการจะ ดำเนินการต่อด้วยการดำเนินการถัดไปใน 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 ให้ทำตามขั้นตอนต่อไปนี้

  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. ใช้ธุรกรรมแบบกลุ่ม

หากการดำเนินการอื่นอัปเดตแถวของข้อมูลติดต่อดิบระหว่างเวลาที่คุณอ่านแถวกับ เวลาที่คุณพยายามแก้ไข "assert" ContentProviderOperation จะล้มเหลว และระบบจะยกเลิกการดำเนินการทั้งชุด จากนั้นคุณสามารถเลือกที่จะลองอีกครั้ง กับกลุ่มหรือการดำเนินการอื่นๆ

ข้อมูลโค้ดต่อไปนี้แสดงวิธีสร้าง "assert" ContentProviderOperation หลังจากค้นหาข้อมูลติดต่อดิบรายการเดียวโดยใช้ CursorLoader

Kotlin

/*
 * The application uses CursorLoader to query the raw contacts table. The system calls this method
 * when the load is finished.
 */
override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) {
    // Gets the raw contact's _ID and VERSION values
    rawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID))
    mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION))
}

...

// Sets up a Uri for the assert operation
val rawContactUri: Uri = ContentUris.withAppendedId(
        ContactsContract.RawContacts.CONTENT_URI,
        rawContactID
)

// Creates a builder for the assert operation
val assertOp: ContentProviderOperation.Builder =
        ContentProviderOperation.newAssertQuery(rawContactUri).apply {
            // Adds the assertions to the assert operation: checks the version
            withValue(SyncColumns.VERSION, mVersion)

            // and count of rows tested
            withExpectedCount(1)
        }

// Creates an ArrayList to hold the ContentProviderOperation objects
val ops = arrayListOf<ContentProviderOperation>()

ops.add(assertOp.build())

// You would add the rest of your batch operations to "ops" here

...

// Applies the batch. If the assert fails, an Exception is thrown
try {
    val results: Array<ContentProviderResult> = contentResolver.applyBatch(AUTHORITY, ops)
} catch (e: OperationApplicationException) {
    // Actions you want to take if the assert operation fails go here
}

Java

/*
 * The application uses CursorLoader to query the raw contacts table. The system calls this method
 * when the load is finished.
 */
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {

    // Gets the raw contact's _ID and VERSION values
    rawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID));
    mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION));
}

...

// Sets up a Uri for the assert operation
Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactID);

// Creates a builder for the assert operation
ContentProviderOperation.Builder assertOp = ContentProviderOperation.newAssertQuery(rawContactUri);

// Adds the assertions to the assert operation: checks the version and count of rows tested
assertOp.withValue(SyncColumns.VERSION, mVersion);
assertOp.withExpectedCount(1);

// Creates an ArrayList to hold the ContentProviderOperation objects
ArrayList ops = new ArrayList<ContentProviderOperation>;

ops.add(assertOp.build());

// You would add the rest of your batch operations to "ops" here

...

// Applies the batch. If the assert fails, an Exception is thrown
try
    {
        ContentProviderResult[] results =
                getContentResolver().applyBatch(AUTHORITY, ops);

    } catch (OperationApplicationException e) {

        // Actions you want to take if the assert operation fails go here
    }

การดึงข้อมูลและการแก้ไขด้วย Intent

การส่ง Intent ไปยังแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์จะช่วยให้คุณเข้าถึง Contacts Provider โดยอ้อมได้ Intent จะเริ่ม UI ของแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ ซึ่งผู้ใช้สามารถ ทำงานที่เกี่ยวข้องกับรายชื่อผู้ติดต่อได้ เมื่อมีสิทธิ์เข้าถึงประเภทนี้ ผู้ใช้จะทำสิ่งต่อไปนี้ได้

  • เลือกรายชื่อติดต่อจากรายการและส่งกลับไปยังแอปของคุณเพื่อดำเนินการต่อ
  • แก้ไขข้อมูลของผู้ติดต่อที่มีอยู่
  • แทรกข้อมูลติดต่อดิบใหม่สำหรับบัญชีใดก็ได้
  • ลบรายชื่อติดต่อหรือข้อมูลรายชื่อติดต่อ

หากผู้ใช้แทรกหรืออัปเดตข้อมูล คุณสามารถรวบรวมข้อมูลก่อนแล้วส่งเป็น ส่วนหนึ่งของ Intent ได้

เมื่อใช้ Intent เพื่อเข้าถึง Contacts Provider ผ่านแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ คุณ ไม่จำเป็นต้องเขียน UI หรือโค้ดของคุณเองเพื่อเข้าถึงผู้ให้บริการ นอกจากนี้ คุณยังไม่จำเป็นต้อง ขอสิทธิ์ในการอ่านหรือเขียนไปยังผู้ให้บริการ แอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์สามารถ มอบสิทธิ์อ่านรายชื่อติดต่อให้คุณได้ และเนื่องจากคุณทำการแก้ไขผู้ให้บริการผ่านแอปพลิเคชันอื่น คุณจึงไม่จำเป็นต้องมีสิทธิ์เขียน

กระบวนการทั่วไปในการส่ง Intent เพื่อเข้าถึงผู้ให้บริการอธิบายไว้โดยละเอียดใน คู่มือพื้นฐานเกี่ยวกับ Content Provider ในส่วน "การเข้าถึงข้อมูลผ่าน Intent" การดำเนินการ ประเภท MIME และค่าข้อมูลที่คุณใช้สำหรับงานที่พร้อมใช้งานจะสรุปไว้ในตารางที่ 4 ส่วนค่า extras ที่คุณใช้กับ putExtra() จะแสดงอยู่ใน เอกสารอ้างอิงสำหรับ ContactsContract.Intents.Insert

ตารางที่ 4 เจตนาของ Contacts Provider

งาน การทำงาน ข้อมูล ประเภท MIME หมายเหตุ
เลือกรายชื่อติดต่อจากรายการ ACTION_PICK ค่าใดค่าหนึ่งต่อไปนี้
  • Contacts.CONTENT_URI ซึ่งจะแสดงรายชื่อติดต่อ
  • Phone.CONTENT_URI ซึ่งแสดงรายการหมายเลขโทรศัพท์สำหรับข้อมูลติดต่อดิบ
  • StructuredPostal.CONTENT_URI ซึ่งจะแสดงรายชื่อที่อยู่ทางไปรษณีย์สำหรับข้อมูลติดต่อดิบ
  • Email.CONTENT_URI ซึ่งแสดงรายการอีเมลสำหรับข้อมูลติดต่อดิบ
ไม่ได้ใช้ แสดงรายการข้อมูลติดต่อดิบหรือรายการข้อมูลจากข้อมูลติดต่อดิบ ทั้งนี้ขึ้นอยู่กับประเภท URI เนื้อหาที่คุณระบุ

Call startActivityForResult(), ซึ่งจะแสดงผล URI เนื้อหาของแถวที่เลือก รูปแบบของ URI คือ URI เนื้อหาของตารางที่มี LOOKUP_ID ของแถวต่อท้าย แอปรายชื่อติดต่อของอุปกรณ์จะมอบสิทธิ์อ่านและเขียนให้กับ URI เนื้อหานี้ ตลอดอายุการใช้งานของกิจกรรม ดูรายละเอียดเพิ่มเติมได้ในคู่มือ ข้อมูลเบื้องต้นเกี่ยวกับผู้ให้บริการเนื้อหา

แทรกข้อมูลติดต่อดิบใหม่ Insert.ACTION ไม่มี RawContacts.CONTENT_TYPE ประเภท MIME สำหรับชุดรายชื่อติดต่อดิบ แสดงหน้าจอเพิ่มรายชื่อติดต่อของแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ ค่า extras ที่คุณเพิ่มลงใน Intent จะแสดงขึ้น หากส่งพร้อมกับ startActivityForResult() ระบบจะส่ง URI เนื้อหาของข้อมูลติดต่อดิบที่เพิ่มใหม่กลับไปยัง onActivityResult() เมธอด Callback ของกิจกรรมในอาร์กิวเมนต์ 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);

ความสมบูรณ์ของข้อมูล

เนื่องจากที่เก็บรายชื่อติดต่อมีข้อมูลที่สำคัญและละเอียดอ่อนซึ่งผู้ใช้คาดหวังว่าข้อมูลดังกล่าวจะถูกต้องและเป็นปัจจุบัน Contacts Provider จึงมีกฎที่กำหนดไว้อย่างชัดเจนสำหรับความสมบูรณ์ของข้อมูล คุณมีหน้าที่รับผิดชอบในการปฏิบัติตามกฎเหล่านี้เมื่อแก้ไขข้อมูลรายชื่อติดต่อ กฎที่สำคัญ มีดังนี้

เพิ่มContactsContract.CommonDataKinds.StructuredNameแถว สําหรับContactsContract.RawContactsแถวทุกแถวที่คุณเพิ่มเสมอ
แถว ContactsContract.RawContacts ที่ไม่มีแถว ContactsContract.CommonDataKinds.StructuredName ในตาราง ContactsContract.Data อาจทำให้เกิดปัญหาในระหว่างการ รวม
ลิงก์แถว ContactsContract.Data ใหม่กับแถว ContactsContract.RawContacts ระดับบนเสมอ
แถว ContactsContract.Data ที่ไม่ได้ลิงก์กับ ContactsContract.RawContacts จะไม่ปรากฏในแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ และอาจทำให้เกิดปัญหากับอะแดปเตอร์การซิงค์
เปลี่ยนข้อมูลเฉพาะรายชื่อติดต่อดิบที่คุณเป็นเจ้าของเท่านั้น
โปรดทราบว่าโดยปกติแล้ว Contacts Provider จะจัดการข้อมูลจากบัญชีประเภทต่างๆ และบริการออนไลน์หลายรายการ คุณต้องตรวจสอบว่าแอปพลิเคชันของคุณแก้ไข หรือลบข้อมูลสำหรับแถวที่เป็นของคุณเท่านั้น และแทรกข้อมูลที่มี ประเภทบัญชีและชื่อที่คุณควบคุมเท่านั้น
ใช้ค่าคงที่ที่กำหนดไว้ใน ContactsContract และคลาสย่อย ของค่าคงที่นั้นเสมอสำหรับค่าของหน่วยงาน, URI ของเนื้อหา, เส้นทาง URI, ชื่อคอลัมน์, ประเภท MIME และTYPE
การใช้ค่าคงที่เหล่านี้จะช่วยให้คุณหลีกเลี่ยงข้อผิดพลาดได้ คุณจะได้รับการแจ้งเตือนพร้อมคำเตือนของคอมไพเลอร์ หากค่าคงที่ใดถูกเลิกใช้งาน

แถวข้อมูลที่กำหนดเอง

การสร้างและใช้ประเภท MIME ที่กำหนดเองจะช่วยให้คุณแทรก แก้ไข ลบ และเรียกข้อมูลแถวข้อมูลของคุณเองในContactsContract.Dataตารางได้ แถว จะใช้ได้เฉพาะคอลัมน์ที่กำหนดไว้ใน ContactsContract.DataColumns แม้ว่าคุณจะแมปชื่อคอลัมน์เฉพาะประเภทของคุณเอง กับชื่อคอลัมน์เริ่มต้นได้ก็ตาม ในแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ ข้อมูลสำหรับแถวของคุณจะแสดงขึ้น แต่จะแก้ไขหรือลบไม่ได้ และผู้ใช้จะเพิ่ม ข้อมูลเพิ่มเติมไม่ได้ หากต้องการอนุญาตให้ผู้ใช้แก้ไขแถวข้อมูลที่กำหนดเอง คุณต้องระบุกิจกรรมของเอดิเตอร์ ในแอปพลิเคชันของคุณเอง

หากต้องการแสดงข้อมูลที่กำหนดเอง ให้ระบุcontacts.xmlไฟล์ที่มีองค์ประกอบ <ContactsAccountType> และองค์ประกอบย่อย <ContactsDataKind> อย่างน้อย 1 รายการ ซึ่งอธิบายไว้อย่างละเอียดในส่วน<ContactsDataKind> element

ดูข้อมูลเพิ่มเติมเกี่ยวกับประเภท MIME ที่กำหนดเองได้ในคู่มือ สร้าง Content Provider

อะแดปเตอร์การซิงค์ Contacts Provider

Contacts Provider ออกแบบมาเพื่อจัดการการซิงค์ ข้อมูลรายชื่อติดต่อระหว่างอุปกรณ์กับบริการออนไลน์โดยเฉพาะ ซึ่งจะช่วยให้ผู้ใช้ดาวน์โหลด ข้อมูลที่มีอยู่ไปยังอุปกรณ์ใหม่และอัปโหลดข้อมูลที่มีอยู่ไปยังบัญชีใหม่ได้ การซิงค์ยังช่วยให้ผู้ใช้มีข้อมูลล่าสุดอยู่ในมือ ไม่ว่า แหล่งที่มาของการเพิ่มและการเปลี่ยนแปลงจะเป็นอะไรก็ตาม ข้อดีอีกอย่างของการซิงค์คือการทำให้ข้อมูลรายชื่อติดต่อพร้อมใช้งานแม้ว่าอุปกรณ์จะไม่ได้เชื่อมต่อกับเครือข่ายก็ตาม

แม้ว่าคุณจะใช้การซิงค์ได้หลายวิธี แต่ระบบ Android มี เฟรมเวิร์กการซิงค์แบบปลั๊กอินที่ทำให้งานต่อไปนี้เป็นไปโดยอัตโนมัติ

  • กำลังตรวจสอบความพร้อมใช้งานของเครือข่าย
  • กำหนดเวลาและดำเนินการซิงค์ตามค่ากำหนดของผู้ใช้
  • การรีสตาร์ทการซิงโครไนซ์ที่หยุดไป

หากต้องการใช้เฟรมเวิร์กนี้ คุณต้องจัดหาปลั๊กอินอะแดปเตอร์การซิงค์ อะแดปเตอร์การซิงค์แต่ละรายการจะเฉพาะเจาะจงสำหรับบริการและ Content Provider แต่สามารถจัดการชื่อบัญชีหลายชื่อสำหรับบริการเดียวกันได้ เฟรมเวิร์กยังอนุญาตให้มี Sync Adapter หลายรายการสำหรับบริการและผู้ให้บริการเดียวกันด้วย

คลาสและไฟล์ของอะแดปเตอร์การซิงค์

คุณใช้ตัวปรับการซิงค์เป็นคลาสย่อยของ AbstractThreadedSyncAdapter และติดตั้งเป็นส่วนหนึ่งของแอปพลิเคชัน Android ระบบจะเรียนรู้เกี่ยวกับอะแดปเตอร์การซิงค์จากองค์ประกอบในไฟล์ Manifest ของแอปพลิเคชัน และจากไฟล์ XML พิเศษที่ไฟล์ Manifest ชี้ไป ไฟล์ XML จะกำหนด ประเภทบัญชีสำหรับบริการออนไลน์และสิทธิ์สำหรับผู้ให้บริการเนื้อหา ซึ่งเมื่อรวมกันแล้ว จะระบุอะแดปเตอร์ได้อย่างไม่ซ้ำกัน อะแดปเตอร์การซิงค์จะไม่ทำงานจนกว่าผู้ใช้จะเพิ่มบัญชีสำหรับประเภทบัญชีของอะแดปเตอร์การซิงค์และเปิดใช้การซิงค์สำหรับ Content Provider ที่อะแดปเตอร์การซิงค์ซิงค์ด้วย ในจุดนั้น ระบบจะเริ่มจัดการอแดปเตอร์ และเรียกใช้อแดปเตอร์ตามความจำเป็นเพื่อซิงค์ระหว่างผู้ให้บริการเนื้อหากับเซิร์ฟเวอร์

หมายเหตุ: การใช้ประเภทบัญชีเป็นส่วนหนึ่งของการระบุตัวตนของอะแดปเตอร์การซิงค์ จะช่วยให้ระบบตรวจหาและจัดกลุ่มอะแดปเตอร์การซิงค์ที่เข้าถึงบริการต่างๆ จากองค์กรเดียวกันได้ เช่น อะแดปเตอร์การซิงค์สำหรับบริการออนไลน์ของ Google ทั้งหมดมี ประเภทบัญชีcom.googleเดียวกัน เมื่อผู้ใช้เพิ่มบัญชี Google ลงในอุปกรณ์ ระบบจะแสดงอะแดปเตอร์การซิงค์ที่ติดตั้งไว้ทั้งหมดสำหรับบริการของ Google ไว้ด้วยกัน โดยอะแดปเตอร์การซิงค์แต่ละรายการที่แสดงจะซิงค์กับ Content Provider ที่แตกต่างกันในอุปกรณ์

เนื่องจากบริการส่วนใหญ่กำหนดให้ผู้ใช้ยืนยันตัวตนก่อนเข้าถึงข้อมูล ระบบ Android จึงมีเฟรมเวิร์กการตรวจสอบสิทธิ์ที่คล้ายกับอะแดปเตอร์การซิงค์ และมักใช้ร่วมกับเฟรมเวิร์กอะแดปเตอร์การซิงค์ เฟรมเวิร์กการตรวจสอบสิทธิ์ใช้ เครื่องมือตรวจสอบสิทธิ์แบบปลั๊กอินซึ่งเป็นคลาสย่อยของ AbstractAccountAuthenticator เครื่องมือตรวจสอบสิทธิ์จะยืนยัน ตัวตนของผู้ใช้ในขั้นตอนต่อไปนี้

  1. รวบรวมชื่อ รหัสผ่าน หรือข้อมูลที่คล้ายกันของผู้ใช้ (ข้อมูลเข้าสู่ระบบของผู้ใช้)
  2. ส่งข้อมูลเข้าสู่ระบบไปยังบริการ
  3. ตรวจสอบการตอบกลับของบริการ

หากบริการยอมรับข้อมูลเข้าสู่ระบบ โปรแกรมตรวจสอบสิทธิ์จะ จัดเก็บข้อมูลเข้าสู่ระบบไว้ใช้ในภายหลังได้ เนื่องจากเฟรมเวิร์กของโปรแกรมตรวจสอบสิทธิ์แบบปลั๊กอิน AccountManager จึงสามารถให้สิทธิ์เข้าถึงโทเค็นการตรวจสอบสิทธิ์ที่โปรแกรมตรวจสอบสิทธิ์ รองรับและเลือกที่จะเปิดเผย เช่น โทเค็นการตรวจสอบสิทธิ์ OAuth2

แม้ว่าการตรวจสอบสิทธิ์จะไม่จำเป็น แต่บริการรายชื่อติดต่อส่วนใหญ่ก็ใช้การตรวจสอบสิทธิ์ อย่างไรก็ตาม คุณไม่จำเป็นต้องใช้เฟรมเวิร์กการตรวจสอบสิทธิ์ของ Android เพื่อทำการตรวจสอบสิทธิ์

การติดตั้งใช้งานอะแดปเตอร์การซิงค์

หากต้องการใช้ตัวดัดแปลงการซิงค์สำหรับ Contacts Provider คุณต้องเริ่มต้นด้วยการสร้างแอปพลิเคชัน Android ที่มีองค์ประกอบต่อไปนี้

คอมโพเนนต์ Service ที่ตอบสนองต่อคำขอจากระบบเพื่อ เชื่อมโยงกับอะแดปเตอร์การซิงค์
เมื่อระบบต้องการเรียกใช้การซิงค์ ระบบจะเรียกใช้เมธอด onBind() ของบริการเพื่อรับ IBinder สำหรับอะแดปเตอร์การซิงค์ ซึ่งจะช่วยให้ระบบ โทรข้ามกระบวนการไปยังเมธอดของอแดปเตอร์ได้
อะแดปเตอร์การซิงค์จริงที่ใช้เป็นคลาสย่อยที่เฉพาะเจาะจงของ AbstractThreadedSyncAdapter
คลาสนี้จะทำหน้าที่ดาวน์โหลดข้อมูลจากเซิร์ฟเวอร์ อัปโหลดข้อมูลจาก อุปกรณ์ และแก้ไขข้อขัดแย้ง การทำงานหลักของอแดปเตอร์ จะดำเนินการในเมธอด onPerformSync() ต้องสร้างอินสแตนซ์ของคลาสนี้เป็น Singleton
คลาสย่อยของ Application
คลาสนี้ทำหน้าที่เป็นโรงงานสำหรับซิงเกิลตันของอะแดปเตอร์การซิงค์ ใช้วิธี onCreate() เพื่อสร้างอินสแตนซ์ของอะแดปเตอร์การซิงค์ และ ระบุเมธอด "Getter" แบบคงที่เพื่อส่งคืน Singleton ไปยัง เมธอด onBind() ของบริการอะแดปเตอร์การซิงค์
ไม่บังคับ: Service คอมโพเนนต์ที่ตอบสนองต่อ คำขอจากระบบสำหรับการตรวจสอบสิทธิ์ผู้ใช้
AccountManager เริ่มบริการนี้เพื่อเริ่มกระบวนการ ตรวจสอบสิทธิ์ เมธอด onCreate() ของบริการจะสร้างออบเจ็กต์ Authenticator เมื่อระบบต้องการตรวจสอบสิทธิ์บัญชีผู้ใช้สำหรับ อะแดปเตอร์การซิงค์ ของแอปพลิเคชัน ระบบจะเรียกใช้เมธอด onBind() ของบริการเพื่อรับ IBinder สำหรับ Authenticator ซึ่งจะช่วยให้ระบบ โทรข้ามกระบวนการไปยังเมธอดของเครื่องมือตรวจสอบสิทธิ์ได้
ไม่บังคับ: คลาสย่อยที่เฉพาะเจาะจงของ AbstractAccountAuthenticator ซึ่งจัดการคำขอสำหรับ การตรวจสอบสิทธิ์
คลาสนี้มีเมธอดที่ AccountManager เรียกใช้ เพื่อตรวจสอบสิทธิ์ข้อมูลเข้าสู่ระบบของผู้ใช้กับเซิร์ฟเวอร์ รายละเอียดของ กระบวนการตรวจสอบสิทธิ์จะแตกต่างกันไปตามเทคโนโลยีเซิร์ฟเวอร์ที่ใช้ คุณควร ดูเอกสารประกอบสำหรับซอฟต์แวร์เซิร์ฟเวอร์เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับการตรวจสอบสิทธิ์
ไฟล์ XML ที่กำหนดอะแดปเตอร์การซิงค์และ Authenticator ให้กับระบบ
คอมโพเนนต์บริการ Authenticator และอะแดปเตอร์การซิงค์ที่อธิบายไว้ก่อนหน้านี้ จะกำหนดไว้ใน <service> ในไฟล์ Manifest ของแอปพลิเคชัน องค์ประกอบเหล่านี้ มีองค์ประกอบย่อย <meta-data> ซึ่งให้ข้อมูลที่เฉพาะเจาะจงแก่ระบบ
  • องค์ประกอบ <meta-data> สำหรับบริการของอะแดปเตอร์การซิงค์จะชี้ไปยัง ไฟล์ XML res/xml/syncadapter.xml ในทางกลับกัน ไฟล์นี้จะระบุ URI สำหรับเว็บเซอร์วิสที่จะซิงค์กับ Contacts Provider และประเภทบัญชีสำหรับเว็บเซอร์วิส
  • ไม่บังคับ: องค์ประกอบ <meta-data> สำหรับเครื่องมือตรวจสอบสิทธิ์จะชี้ไปยังไฟล์ XML res/xml/authenticator.xml ซึ่งไฟล์นี้จะระบุ ประเภทบัญชีที่เครื่องมือตรวจสอบสิทธิ์นี้รองรับ รวมถึงทรัพยากร UI ที่ ปรากฏในระหว่างกระบวนการตรวจสอบสิทธิ์ ประเภทบัญชีที่ระบุในองค์ประกอบนี้ต้องเหมือนกับประเภทบัญชีที่ระบุสำหรับอะแดปเตอร์การซิงค์

ข้อมูลสตรีมโซเชียล

ตาราง android.provider.ContactsContract.StreamItems และ android.provider.ContactsContract.StreamItemPhotos จัดการข้อมูลที่เข้ามาจากโซเชียลเน็ตเวิร์ก คุณเขียนอะแดปเตอร์การซิงค์ที่เพิ่มข้อมูลสตรีม จากเครือข่ายของคุณเองลงในตารางเหล่านี้ หรือจะอ่านข้อมูลสตรีมจากตารางเหล่านี้และ แสดงในแอปพลิเคชันของคุณเอง หรือทั้ง 2 อย่างก็ได้ ฟีเจอร์เหล่านี้ช่วยให้คุณผสานรวมบริการและแอปพลิเคชันเครือข่ายสังคมออนไลน์ เข้ากับประสบการณ์การใช้งานเครือข่ายสังคมออนไลน์ของ Android ได้

ข้อความสตรีมโซเชียล

รายการสตรีมจะเชื่อมโยงกับข้อมูลติดต่อดิบเสมอ The android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID links to the _ID value for the raw contact. ระบบจะจัดเก็บประเภทบัญชีและชื่อบัญชีของรายชื่อติดต่อดิบ ไว้ในแถวของรายการสตรีมด้วย

จัดเก็บข้อมูลจากสตรีมในคอลัมน์ต่อไปนี้

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 ระบบจะจำกัดจำนวนแถว ที่จัดเก็บไว้สำหรับข้อมูลติดต่อดิบแต่ละรายการ เมื่อถึงขีดจำกัดนี้แล้ว Contacts Provider จะเพิ่มพื้นที่สำหรับแถวรายการสตรีมใหม่โดยการลบแถวที่มี 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 ที่มีแถวรูปภาพสำหรับสตรีมไอเทมเดียว

การโต้ตอบในสตรีมโซเชียล

ข้อมูลสตรีมโซเชียลที่จัดการโดย Contacts Provider ร่วมกับแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์เป็นวิธีที่มีประสิทธิภาพในการเชื่อมต่อระบบโซเชียลเน็ตเวิร์กกับรายชื่อติดต่อที่มีอยู่ ฟีเจอร์ต่อไปนี้พร้อมใช้งาน

  • การซิงค์บริการเครือข่ายสังคมกับ Contacts Provider ด้วยอะแดปเตอร์การซิงค์ จะช่วยให้คุณดึงกิจกรรมล่าสุดของรายชื่อติดต่อของผู้ใช้และจัดเก็บไว้ในตาราง android.provider.ContactsContract.StreamItems และ android.provider.ContactsContract.StreamItemPhotos เพื่อใช้ในภายหลังได้
  • นอกจากการซิงค์ปกติแล้ว คุณยังเรียกใช้ตัวดัดแปลงการซิงค์เพื่อดึงข้อมูลเพิ่มเติมได้เมื่อผู้ใช้เลือกรายชื่อติดต่อเพื่อดู ซึ่งจะช่วยให้ อะแดปเตอร์การซิงค์ ดึงรูปภาพความละเอียดสูงและรายการสตรีมล่าสุดสำหรับรายชื่อติดต่อได้
  • การลงทะเบียนการแจ้งเตือนกับแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์และ Contacts Provider จะช่วยให้คุณรับ Intent เมื่อมีการดูรายชื่อติดต่อ และอัปเดตสถานะของรายชื่อติดต่อจากบริการของคุณได้ในเวลานั้น วิธีนี้อาจเร็วกว่าและใช้แบนด์วิดท์น้อยกว่าการซิงค์แบบเต็มด้วยอะแดปเตอร์การซิงค์
  • ผู้ใช้สามารถเพิ่มรายชื่อติดต่อลงในบริการเครือข่ายสังคมขณะดูรายชื่อติดต่อ ในแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ คุณเปิดใช้ฟีเจอร์นี้ได้ด้วยฟีเจอร์ "เชิญรายชื่อติดต่อ" ซึ่งคุณเปิดใช้ได้ด้วยการรวมกิจกรรมที่เพิ่มรายชื่อติดต่อที่มีอยู่ลงในเครือข่ายของคุณ และไฟล์ XML ที่ให้รายละเอียดแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์และ Contacts Provider พร้อมรายละเอียดของแอปพลิเคชันของคุณ

การซิงค์รายการในสตรีมกับ Contacts Provider เป็นประจำจะเหมือนกับการซิงค์อื่นๆ ดูข้อมูลเพิ่มเติมเกี่ยวกับการซิงค์ได้ที่ส่วน อะแดปเตอร์การซิงค์ของ Contacts Provider การลงทะเบียนการแจ้งเตือนและ การเชิญผู้ติดต่อจะกล่าวถึงใน 2 ส่วนถัดไป

การลงทะเบียนเพื่อจัดการการดูโซเชียลเน็ตเวิร์ก

หากต้องการลงทะเบียนอะแดปเตอร์การซิงค์เพื่อรับการแจ้งเตือนเมื่อผู้ใช้ดูรายชื่อติดต่อที่ อะแดปเตอร์การซิงค์ของคุณจัดการ ให้ทำดังนี้

  1. สร้างไฟล์ชื่อ contacts.xml ในไดเรกทอรี res/xml/ ของโปรเจ็กต์ หากมีไฟล์นี้อยู่แล้ว ให้ข้ามขั้นตอนนี้
  2. ในไฟล์นี้ ให้เพิ่มองค์ประกอบ <ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"> หากมีองค์ประกอบนี้อยู่แล้ว ให้ข้ามขั้นตอนนี้
  3. หากต้องการลงทะเบียนบริการที่จะได้รับการแจ้งเตือนเมื่อผู้ใช้เปิดหน้ารายละเอียดของรายชื่อผู้ติดต่อใน แอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ ให้เพิ่มแอตทริบิวต์ viewContactNotifyService="serviceclass" ไปยังองค์ประกอบ โดยที่ serviceclass คือชื่อคลาสที่มีคุณสมบัติครบถ้วนของบริการ ที่ควรได้รับ Intent จากแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ สำหรับบริการแจ้งเตือน ให้ใช้คลาสที่ขยาย IntentService เพื่อให้บริการรับ Intent ได้ ข้อมูลใน Intent ขาเข้ามี URI เนื้อหาของรายชื่อติดต่อดิบที่ผู้ใช้คลิก จากบริการแจ้งเตือน คุณสามารถเชื่อมโยงและเรียกใช้ อะแดปเตอร์การซิงค์ เพื่ออัปเดตข้อมูลสำหรับข้อมูลติดต่อดิบ

หากต้องการลงทะเบียนกิจกรรมที่จะเรียกใช้เมื่อผู้ใช้คลิกรายการในสตรีมหรือรูปภาพ หรือทั้ง 2 อย่าง ให้ทำดังนี้

  1. สร้างไฟล์ชื่อ contacts.xml ในไดเรกทอรี res/xml/ ของโปรเจ็กต์ หากมีไฟล์นี้อยู่แล้ว ให้ข้ามขั้นตอนนี้
  2. ในไฟล์นี้ ให้เพิ่มองค์ประกอบ <ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"> หากมีองค์ประกอบนี้อยู่แล้ว ให้ข้ามขั้นตอนนี้
  3. หากต้องการลงทะเบียนกิจกรรมอย่างใดอย่างหนึ่งเพื่อจัดการเมื่อผู้ใช้คลิกรายการในสตรีมในแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ ให้เพิ่มแอตทริบิวต์ viewStreamItemActivity="activityclass" ลงในองค์ประกอบ โดยที่ activityclass คือชื่อคลาสแบบเต็มของกิจกรรม ที่ควรรับ Intent จากแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์
  4. หากต้องการลงทะเบียนกิจกรรมอย่างใดอย่างหนึ่งเพื่อจัดการเมื่อผู้ใช้คลิกรูปภาพในสตรีมในแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ ให้เพิ่มแอตทริบิวต์ viewStreamItemPhotoActivity="activityclass" ลงในองค์ประกอบ โดยที่ activityclass คือชื่อคลาสแบบเต็มของกิจกรรม ที่ควรรับ Intent จากแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์

องค์ประกอบ <ContactsAccountType> มีคำอธิบายโดยละเอียดในส่วนองค์ประกอบ<ContactsAccountType>

Intent ขาเข้ามี URI เนื้อหาของรายการหรือรูปภาพที่ผู้ใช้คลิก หากต้องการมีกิจกรรมแยกกันสำหรับรายการข้อความและรูปภาพ ให้ใช้ทั้ง 2 แอตทริบิวต์ในไฟล์เดียวกัน

การโต้ตอบกับบริการโซเชียลเน็ตเวิร์ก

ผู้ใช้ไม่จำเป็นต้องออกจากแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์เพื่อเชิญรายชื่อติดต่อไปยังเว็บไซต์โซเชียลเน็ตเวิร์กของคุณ แต่คุณสามารถให้แอปรายชื่อติดต่อของอุปกรณ์ส่ง Intent เพื่อเชิญ รายชื่อติดต่อเข้าร่วมกิจกรรมอย่างใดอย่างหนึ่งของคุณได้ โดยมีวิธีการตั้งค่าดังนี้

  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 คือสตริงข้อความที่แสดงในเมนูเพิ่มการเชื่อมต่อในแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์

หมายเหตุ: ContactsSource เป็นชื่อแท็กที่เลิกใช้งานแล้วสำหรับ ContactsAccountType

การอ้างอิง contacts.xml

ไฟล์ contacts.xml มีองค์ประกอบ XML ที่ควบคุมการโต้ตอบของอะแดปเตอร์การซิงค์และแอปพลิเคชันกับแอปพลิเคชันรายชื่อผู้ติดต่อและ Contacts Provider องค์ประกอบเหล่านี้มีคำอธิบายในส่วนต่อไปนี้

องค์ประกอบ <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 และป้ายกำกับ 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>

คำอธิบาย:

ใช้องค์ประกอบนี้เพื่อให้แอปพลิเคชันรายชื่อผู้ติดต่อแสดงเนื้อหาของแถวข้อมูลที่กำหนดเองเป็น ส่วนหนึ่งของรายละเอียดของข้อมูลติดต่อดิบ <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

นอกเหนือจากฟีเจอร์หลักที่อธิบายไว้ในส่วนก่อนหน้าแล้ว Contacts Provider ยังมีฟีเจอร์ที่มีประโยชน์ต่อไปนี้สำหรับการทำงานกับข้อมูลรายชื่อติดต่อ

  • กลุ่มรายชื่อติดต่อ
  • ฟีเจอร์รูปภาพ

กลุ่มรายชื่อติดต่อ

Contacts Provider จะติดป้ายกำกับคอลเล็กชันของรายชื่อติดต่อที่เกี่ยวข้องด้วยข้อมูลกลุ่มหรือไม่ก็ได้ หากเซิร์ฟเวอร์ที่เชื่อมโยงกับบัญชีผู้ใช้ ต้องการรักษากลุ่มไว้ อะแดปเตอร์การซิงค์สำหรับประเภทบัญชีของบัญชีนั้นควรโอน ข้อมูลกลุ่มระหว่าง Contacts Provider กับเซิร์ฟเวอร์ เมื่อผู้ใช้เพิ่มรายชื่อติดต่อใหม่ลงในเซิร์ฟเวอร์ แล้วใส่รายชื่อติดต่อนี้ในกลุ่มใหม่ อะแดปเตอร์การซิงค์จะต้องเพิ่มกลุ่มใหม่ ลงในตาราง ContactsContract.Groups ระบบจะจัดเก็บกลุ่มที่รายชื่อติดต่อดิบ เป็นสมาชิกไว้ในตาราง ContactsContract.Data โดยใช้ ประเภท MIME ของ ContactsContract.CommonDataKinds.GroupMembership

หากคุณกำลังออกแบบอะแดปเตอร์การซิงค์ที่จะเพิ่มข้อมูลติดต่อดิบจากเซิร์ฟเวอร์ไปยัง Contacts Provider และไม่ได้ใช้กลุ่ม คุณจะต้องบอกให้ Provider ทำให้ข้อมูลของคุณปรากฏ ในโค้ดที่เรียกใช้เมื่อผู้ใช้เพิ่มบัญชี ลงในอุปกรณ์ ให้อัปเดตแถว ContactsContract.Settings ที่ Contacts Provider เพิ่มสำหรับบัญชี ในแถวนี้ ให้ตั้งค่าของคอลัมน์ Settings.UNGROUPED_VISIBLE เป็น 1 เมื่อทำเช่นนี้ Contacts Provider จะทำให้ข้อมูลรายชื่อติดต่อของคุณมองเห็นได้เสมอ แม้ว่าคุณจะไม่ได้ใช้กลุ่มก็ตาม

รูปภาพผู้ติดต่อ

ตาราง 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 ซึ่งมีคำอธิบายโดยละเอียดเพิ่มเติมในส่วนรูปภาพในสตรีมโซเชียล