Contacts Provider

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

คู่มือนี้จะอธิบายข้อมูลต่อไปนี้

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

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

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

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

รูปที่ 1 โครงสร้างตารางผู้ให้บริการรายชื่อติดต่อ

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

หมายเหตุ

ข้อมูลสำคัญเกี่ยวกับ ตาราง ContactsContract.RawContacts:

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

    ตัวอย่างเช่น หากต้องการให้แอปดูแลรักษาข้อมูลรายชื่อติดต่อสำหรับบริการบนเว็บที่มีโดเมน 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 เปิด รายชื่อติดต่อ แล้วเพิ่ม "โทมัส ฮิกกินสัน" ต่อมา เธอเข้าสู่ระบบ Gmail โดยใช้บัญชี emilyd@gmail.com และส่งอีเมลถึง "Thomas Higginson" ซึ่งจะเพิ่มเขาเป็นรายชื่อติดต่อโดยอัตโนมัติ นอกจากนี้ เธอยังติดตาม "colonel_tom" (รหัส Twitter ของ Thomas Higginson) บน Twitter ด้วย

ผู้ให้บริการ Contacts จะสร้างรายชื่อติดต่อดิบ 3 รายการจากการดำเนินการนี้ ดังนี้

  1. ข้อมูลติดต่อดิบของ "Thomas Higginson" ที่เชื่อมโยงกับ emily.dickinson@gmail.com ประเภทบัญชีผู้ใช้คือ Google
  2. ข้อมูลติดต่อดิบครั้งที่ 2 ของ "โทมัส ฮิกกินสัน" ซึ่งเชื่อมโยงกับ emilyd@gmail.com ประเภทบัญชีผู้ใช้คือ Google ด้วย มีรายชื่อติดต่อดิบรายการที่ 2 แม้ว่าชื่อจะเหมือนกับชื่อก่อนหน้า เนื่องจากมีการเพิ่มบุคคลนั้นในบัญชีผู้ใช้อื่น
  3. ข้อมูลติดต่อดิบครั้งที่ 3 ของ "โทมัส ฮิกกินสัน" ที่เชื่อมโยงกับ "belle_of_amherst" ผู้ใช้ ประเภทบัญชีคือ Twitter

ข้อมูล

ดังที่กล่าวไว้ก่อนหน้านี้ ข้อมูลสำหรับรายชื่อติดต่อดิบจะเก็บอยู่ใน ContactsContract.Data แถวที่ลิงก์กับรายชื่อติดต่อดิบ _ID ซึ่งจะช่วยให้รายชื่อติดต่อดิบรายการเดียวมีอินสแตนซ์เดียวกันหลายรายการได้ ประเภทข้อมูล เช่น อีเมลหรือหมายเลขโทรศัพท์ ตัวอย่างเช่น หาก "Thomas Higginson" สำหรับ emilyd@gmail.com (แถวรายชื่อติดต่อดิบของ Thomas Higginson ที่เชื่อมโยงกับบัญชี Google emilyd@gmail.com) มีอีเมลบ้านเป็น thigg@gmail.com และอีเมลงานเป็น thomas.higginson@gmail.com ผู้ให้บริการรายชื่อติดต่อจะจัดเก็บแถวอีเมล 2 แถวดังกล่าวและลิงก์ทั้ง 2 แถวกับรายชื่อติดต่อดิบ

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

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

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

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

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

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

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

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

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

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

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

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

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

หากต้องการยืนยันว่าฟังก์ชันการทำงานของแอปไม่ได้รับผลกระทบจากการเปลี่ยนแปลงนี้ คุณสามารถล้างช่องข้อมูลเหล่านี้ด้วยตนเองได้ ในการดำเนินการดังกล่าว ให้เรียกใช้ ADB ต่อไปนี้ ในอุปกรณ์ที่ใช้ Android 4.1 (API ระดับ 16) ขึ้นไป:

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

ข้อมูลจากอะแดปเตอร์การซิงค์

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

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

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

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

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

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

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

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

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

"1" - มีการเปลี่ยนแปลงตั้งแต่การซิงค์ครั้งล่าสุด ต้องซิงค์กลับไปที่เซิร์ฟเวอร์
ContactsContract.RawContacts VERSION หมายเลขเวอร์ชันของแถวนี้ ผู้ให้บริการรายชื่อติดต่อจะเพิ่มค่านี้โดยอัตโนมัติทุกครั้งที่มีการเปลี่ยนแปลงแถวหรือข้อมูลที่เกี่ยวข้อง
ContactsContract.Data DATA_VERSION หมายเลขเวอร์ชันของแถวนี้ ผู้ให้บริการรายชื่อติดต่อจะเพิ่มค่านี้โดยอัตโนมัติเมื่อแถวข้อมูล มีการเปลี่ยนแปลง
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 โดยค่าเริ่มต้น รายชื่อติดต่อจะมองไม่เห็นหากรายชื่อติดต่อดิบไม่มีรายชื่อติดต่อใดอยู่ในกลุ่ม (การเป็นสมาชิกกลุ่มของรายชื่อติดต่อดิบจะระบุด้วยContactsContract.CommonDataKinds.GroupMembershipแถวหรือมากกว่านั้นในตาราง ContactsContract.Data) ตั้งค่าแฟล็กนี้ในแถว ContactsContract.Settings ของตาราง สำหรับประเภทบัญชีและบัญชี คุณสามารถบังคับให้แสดงผู้ติดต่อที่ไม่มีกลุ่มได้ การใช้ธงนี้อย่างหนึ่งคือการแสดงรายชื่อติดต่อจากเซิร์ฟเวอร์ที่ไม่ได้ใช้กลุ่ม
"1" - สำหรับบัญชีและประเภทบัญชีนี้ รายชื่อติดต่อที่ไม่ได้อยู่ในกลุ่มจะแสดงใน UI ของแอปพลิเคชัน
ContactsContract.SyncState (ทั้งหมด) ใช้ตารางนี้เพื่อจัดเก็บข้อมูลเมตาสำหรับอะแดปเตอร์การซิงค์ ตารางนี้ช่วยให้คุณจัดเก็บสถานะการซิงค์และข้อมูลอื่นๆ ที่เกี่ยวข้องกับการซิงค์อย่างถาวรในอุปกรณ์ได้

การเข้าถึง Contacts Provider

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

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

การแก้ไขจากอะแดปเตอร์การซิงค์ยังมีรายละเอียดเพิ่มเติมในส่วนอะแดปเตอร์การซิงค์ของ Contacts Provider

การค้นหาเอนทิตี

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

ข้อมูลโค้ดนี้นำมาจากกิจกรรม "detail"

Kotlin

...
    /*
     * Appends the entity path to the URI. In the case of the Contacts Provider, the
     * expected URI is content://com.google.contacts/#/entity (# is the ID value).
     */
    contactUri = Uri.withAppendedPath(
            contactUri,
            ContactsContract.Contacts.Entity.CONTENT_DIRECTORY
    )

    // Initializes the loader identified by LOADER_ID.
    loaderManager.initLoader(
            LOADER_ID,  // The identifier of the loader to initialize
            null,       // Arguments for the loader (in this case, none)
            this        // The context of the activity
    )

    // Creates a new cursor adapter to attach to the list view
    cursorAdapter = SimpleCursorAdapter(
            this,                       // the context of the activity
            R.layout.detail_list_item,  // the view item containing the detail widgets
            mCursor,                    // the backing cursor
            fromColumns,               // the columns in the cursor that provide the data
            toViews,                   // the views in the view item that display the data
            0)                          // flags

    // Sets the ListView's backing adapter.
    rawContactList.adapter = cursorAdapter
...
override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> {
    /*
     * Sets the columns to retrieve.
     * RAW_CONTACT_ID is included to identify the raw contact associated with the data row.
     * DATA1 contains the first column in the data row (usually the most important one).
     * MIMETYPE indicates the type of data in the data row.
     */
    val projection: Array<String> = arrayOf(
            ContactsContract.Contacts.Entity.RAW_CONTACT_ID,
            ContactsContract.Contacts.Entity.DATA1,
            ContactsContract.Contacts.Entity.MIMETYPE
    )

    /*
     * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw
     * contact collated together.
     */
    val sortOrder = "${ContactsContract.Contacts.Entity.RAW_CONTACT_ID} ASC"

    /*
     * Returns a new CursorLoader. The arguments are similar to
     * ContentResolver.query(), except for the Context argument, which supplies the location of
     * the ContentResolver to use.
     */
    return CursorLoader(
            applicationContext, // The activity's context
            contactUri,        // The entity content URI for a single contact
            projection,         // The columns to retrieve
            null,               // Retrieve all the raw contacts and their data rows.
            null,               //
            sortOrder           // Sort by the raw contact ID.
    )
}

Java

...
    /*
     * Appends the entity path to the URI. In the case of the Contacts Provider, the
     * expected URI is content://com.google.contacts/#/entity (# is the ID value).
     */
    contactUri = Uri.withAppendedPath(
            contactUri,
            ContactsContract.Contacts.Entity.CONTENT_DIRECTORY);

    // Initializes the loader identified by LOADER_ID.
    getLoaderManager().initLoader(
            LOADER_ID,  // The identifier of the loader to initialize
            null,       // Arguments for the loader (in this case, none)
            this);      // The context of the activity

    // Creates a new cursor adapter to attach to the list view
    cursorAdapter = new SimpleCursorAdapter(
            this,                        // the context of the activity
            R.layout.detail_list_item,   // the view item containing the detail widgets
            mCursor,                     // the backing cursor
            fromColumns,                // the columns in the cursor that provide the data
            toViews,                    // the views in the view item that display the data
            0);                          // flags

    // Sets the ListView's backing adapter.
    rawContactList.setAdapter(cursorAdapter);
...
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {

    /*
     * Sets the columns to retrieve.
     * RAW_CONTACT_ID is included to identify the raw contact associated with the data row.
     * DATA1 contains the first column in the data row (usually the most important one).
     * MIMETYPE indicates the type of data in the data row.
     */
    String[] projection =
        {
            ContactsContract.Contacts.Entity.RAW_CONTACT_ID,
            ContactsContract.Contacts.Entity.DATA1,
            ContactsContract.Contacts.Entity.MIMETYPE
        };

    /*
     * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw
     * contact collated together.
     */
    String sortOrder =
            ContactsContract.Contacts.Entity.RAW_CONTACT_ID +
            " ASC";

    /*
     * Returns a new CursorLoader. The arguments are similar to
     * ContentResolver.query(), except for the Context argument, which supplies the location of
     * the ContentResolver to use.
     */
    return new CursorLoader(
            getApplicationContext(),  // The activity's context
            contactUri,              // The entity content URI for a single contact
            projection,               // The columns to retrieve
            null,                     // Retrieve all the raw contacts and their data rows.
            null,                     //
            sortOrder);               // Sort by the raw contact ID.
}

เมื่อโหลดเสร็จแล้ว LoaderManager จะเรียกใช้การเรียกกลับเพื่อไปที่ onLoadFinished() อาร์กิวเมนต์ขาเข้าอย่างหนึ่งของเมธอดนี้คือ Cursor ที่มีผลการค้นหา ในแอปของคุณเอง คุณสามารถเรียกใช้ จาก Cursor นี้เพื่อแสดงหรือทำงานร่วมกับ Google ต่อไป

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

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

  1. ดึงข้อมูลคอลัมน์ VERSION ของรายชื่อติดต่อดิบพร้อมกับข้อมูลอื่นๆ ที่คุณดึงมา
  2. สร้างออบเจ็กต์ ContentProviderOperation.Builder ที่เหมาะสมสําหรับการบังคับใช้ข้อจํากัดโดยใช้เมธอด newAssertQuery(Uri) สำหรับ URI ของเนื้อหา ให้ใช้ RawContacts.CONTENT_URI โดยต่อท้ายด้วย _ID ของข้อมูลติดต่อดิบ
  3. สําหรับออบเจ็กต์ ContentProviderOperation.Builder ให้เรียกใช้ withValue() เพื่อเปรียบเทียบคอลัมน์ VERSION กับหมายเลขเวอร์ชันที่คุณเพิ่งดึงข้อมูล
  4. สําหรับ ContentProviderOperation.Builder เดียวกัน ให้เรียกใช้ withExpectedCount() เพื่อให้แน่ใจว่าการยืนยันนี้ทดสอบเพียง 1 แถวเท่านั้น
  5. เรียกใช้ build() เพื่อสร้างออบเจ็กต์ ContentProviderOperation จากนั้นเพิ่มออบเจ็กต์นี้เป็นออบเจ็กต์แรกใน ArrayList ที่ส่งไปยัง applyBatch()
  6. ใช้ธุรกรรมกลุ่ม

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

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

Kotlin

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

...

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

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

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

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

ops.add(assertOp.build())

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

...

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

Java

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

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

...

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

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

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

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

ops.add(assertOp.build());

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

...

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

    } catch (OperationApplicationException e) {

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

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

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

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

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

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

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

ตาราง 4 Intent ของ Contacts Provider

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

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

แทรกรายชื่อติดต่อใหม่ในรูปแบบไฟล์ RAW Insert.ACTION ไม่มี RawContacts.CONTENT_TYPE, ประเภท MIME สำหรับชุดรายชื่อติดต่อดิบ แสดงหน้าจอเพิ่มรายชื่อติดต่อของแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ ค่าพิเศษที่คุณเพิ่มลงใน Intent จะแสดงขึ้น หากส่งด้วย startActivityForResult() ระบบจะส่ง URI เนื้อหาของรายชื่อติดต่อแบบไฟล์ข้อมูลดิบซึ่งเพิ่มเข้ามาใหม่กลับไปยังonActivityResult()วิธีเรียกกลับของกิจกรรมในอาร์กิวเมนต์ Intent ในช่อง "data" หากต้องการรับค่า ให้เรียกใช้ getData()
แก้ไขรายชื่อติดต่อ ACTION_EDIT CONTENT_LOOKUP_URI สำหรับ รายชื่อติดต่อนั้น กิจกรรมของเครื่องมือแก้ไขจะช่วยให้ผู้ใช้แก้ไขข้อมูลที่เชื่อมโยงกับรายชื่อติดต่อนี้ได้ Contacts.CONTENT_ITEM_TYPE รายชื่อติดต่อรายการเดียว แสดงหน้าจอแก้ไขรายชื่อติดต่อในแอปพลิเคชันรายชื่อติดต่อ ค่าเพิ่มเติมที่คุณเพิ่ม กับความตั้งใจของคุณ เมื่อผู้ใช้คลิกเสร็จสิ้นเพื่อบันทึกการแก้ไข กิจกรรมของคุณจะกลับมาอยู่เบื้องหน้า
แสดงเครื่องมือเลือกที่เพิ่มข้อมูลได้ด้วย ACTION_INSERT_OR_EDIT ไม่มี CONTENT_ITEM_TYPE Intent นี้จะแสดงหน้าจอเครื่องมือเลือกของแอปรายชื่อติดต่อเสมอ ผู้ใช้เลือกดำเนินการต่อไปนี้ได้ เลือกรายชื่อติดต่อที่จะแก้ไข หรือเพิ่มรายชื่อติดต่อใหม่ หน้าจอแก้ไขหรือเพิ่มจะปรากฏขึ้น ทั้งนี้ขึ้นอยู่กับตัวเลือกของผู้ใช้ และข้อมูลเสริมที่คุณส่งใน Intent จะแสดงขึ้น หากแอปแสดงข้อมูลติดต่อ เช่น อีเมลหรือหมายเลขโทรศัพท์ ให้ใช้ 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 และคลาสย่อยของ ContactsContract เสมอสําหรับหน่วยงาน URI ของเนื้อหา เส้นทาง URI ชื่อคอลัมน์ ประเภท MIME และค่า TYPE
การใช้ค่าคงที่เหล่านี้จะช่วยให้คุณหลีกเลี่ยงข้อผิดพลาดได้ นอกจากนี้ คุณยังจะได้รับคำเตือนจากคอมไพเลอร์หากมีการเลิกใช้งานค่าคงที่

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

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

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

หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับประเภท MIME ที่กำหนดเอง โปรดอ่าน คำแนะนำสำหรับการสร้างผู้ให้บริการเนื้อหา

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

รายการสตรีมจะเชื่อมโยงกับรายชื่อติดต่อดิบเสมอ android.provider.ContactsContract.StreamItemsColumn#RAW_CONTACT_ID ลิงก์ไปยัง ค่า _ID สำหรับรายชื่อติดต่อดิบ ระบบจะจัดเก็บประเภทบัญชีและชื่อบัญชีของข้อมูลติดต่อดิบไว้ในแถวรายการสตรีมด้วย

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

android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE
ต้องระบุ ประเภทบัญชีของผู้ใช้สำหรับข้อมูลติดต่อดิบซึ่งเชื่อมโยงกับรายการสตรีมนี้ อย่าลืมตั้งค่านี้เมื่อคุณแทรกรายการสตรีม
android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME
ต้องระบุ ชื่อบัญชีของผู้ใช้สำหรับรายชื่อติดต่อดิบที่เชื่อมโยงกับบัญชีนี้ รายการสตรีม อย่าลืมตั้งค่านี้เมื่อคุณแทรกรายการสตรีม
คอลัมน์ตัวระบุ
ต้องระบุ คุณต้องแทรกคอลัมน์ตัวระบุต่อไปนี้เมื่อ แทรกรายการสตรีมโดยทำดังนี้
  • android.provider.ContactsContract.StreamItemsColumn#CONTACT_ID: ค่า android.provider.BaseColumn#_ID ของรายชื่อติดต่อที่สตรีมนี้ เชื่อมโยงกับรายการ
  • android.provider.ContactsContract.StreamItemsColumn#CONTACT_LOOKUP_KEY: ค่า android.provider.ContactsContract.Contactsระดับบนสุด#LOOKUP_KEY ของค่า รายชื่อติดต่อที่เชื่อมโยงกับรายการสตรีมนี้
  • android.provider.ContactsContract.StreamItemsColumn#RAW_CONTACT_ID: ค่า android.provider.BaseColumn#_ID ของรายชื่อติดต่อดิบที่สตรีมนี้ เชื่อมโยงกับรายการ
android.provider.ContactsContract.StreamItemsColumn#COMMENTS
(ไม่บังคับ) จัดเก็บข้อมูลสรุปที่คุณสามารถแสดงในช่วงต้นของรายการสตรีม
android.provider.ContactsContract.StreamItemsColumn#TEXT
ข้อความของรายการสตรีม ซึ่งอาจเป็นเนื้อหาที่โพสต์โดยแหล่งที่มาของรายการ หรือคำอธิบายการกระทำบางอย่างที่สร้างรายการสตรีม คอลัมน์นี้อาจมีการจัดรูปแบบและรูปภาพแหล่งข้อมูลที่ฝังซึ่งfromHtml()แสดงผลได้ ผู้ให้บริการอาจตัดหรือ เนื้อหาแบบยาวแบบ Ellipsize แต่จะพยายามหลีกเลี่ยงการทำให้แท็กเสียหาย
android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP
สตริงข้อความที่มีเวลาที่แทรกหรืออัปเดตรายการสตรีมในรูปแบบมิลลิวินาทีนับจากจุดเริ่มต้น แอปพลิเคชันที่แทรกหรืออัปเดตรายการสตรีมมีหน้าที่รับผิดชอบในการดูแลรักษาคอลัมน์นี้ ผู้ให้บริการรายชื่อติดต่อจะไม่เป็นผู้ดูแลรักษาโดยอัตโนมัติ

ในการแสดงข้อมูลระบุตัวตนสำหรับรายการสตรีม ให้ใช้ android.provider.ContactsContract.StreamItemsColumn#RES_ICON android.provider.ContactsContract.StreamItemsColumn#RES_LABEL และ android.provider.ContactsContract.StreamItemsColumn#RES_PACKAGE เพื่อลิงก์ไปยังทรัพยากร ในแอปพลิเคชันของคุณ

นอกจากนี้ ตาราง android.provider.ContactsContract.StreamItems จะมีคอลัมน์ต่างๆ ด้วย android.provider.ContactsContract.StreamItemsColumn#SYNC1 ผ่าน android.provider.ContactsContract.StreamItemsColumn#SYNC4 สำหรับการใช้งานเฉพาะ อะแดปเตอร์การซิงค์

รูปภาพสตรีมบนโซเชียล

ตาราง android.provider.ContactsContract.StreamItemPhotos จัดเก็บรูปภาพที่เชื่อมโยงกับรายการสตรีม คอลัมน์ android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID ของตารางจะลิงก์กับค่าในคอลัมน์ _ID ของตาราง android.provider.ContactsContract.StreamItems ระบบจะจัดเก็บข้อมูลอ้างอิงรูปภาพไว้ในตารางในคอลัมน์ต่อไปนี้

คอลัมน์ android.provider.ContactsContract.StreamItemPhotos#PHOTO (BLOB)
การแสดงรูปภาพแบบไบนารี ซึ่งปรับขนาดโดยผู้ให้บริการเพื่อจัดเก็บและแสดงผล คอลัมน์นี้ใช้สำหรับการทำงานร่วมกันแบบย้อนหลังกับรายชื่อติดต่อเวอร์ชันก่อนหน้า ผู้ให้บริการที่ใช้ที่เก็บข้อมูลนี้เพื่อเก็บรูปภาพ อย่างไรก็ตาม ในเวอร์ชันปัจจุบัน คุณไม่ควรใช้คอลัมน์นี้ในการเก็บรูปภาพ แต่ให้ใช้ android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID หรือ android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI (ทั้ง 2 รายการอธิบายไว้ในหัวข้อต่อไปนี้) เพื่อจัดเก็บรูปภาพในไฟล์ คอลัมน์นี้เลย มีภาพขนาดย่อของรูปภาพ ซึ่งสามารถอ่านได้
android.provider.ContactsContract.StreamItemPhotosColumn#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.StreamItemsColumn#TIMESTAMP หากต้องการดาวน์โหลด จำกัด ส่งคำค้นหาไปยัง URI เนื้อหา android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI คุณสามารถตั้งค่าอาร์กิวเมนต์ทั้งหมดเป็น null ยกเว้น URI ของเนื้อหา คำค้นหา จะแสดงผลเคอร์เซอร์ที่มีแถวเดียว โดยมีคอลัมน์เดียว android.provider.ContactsContract.StreamItems#MAX_ITEMS

คลาส android.provider.ContactsContract.StreamItems.StreamItemPhotos จะระบุ ตารางย่อยของ android.provider.ContactsContract.StreamItemPhotos ที่มีรูปภาพ แถวสำหรับรายการสตรีมเดียว

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

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

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

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

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

  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 รายการในไฟล์เดียวกัน

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

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

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

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

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

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

<ContactsAccountType> องค์ประกอบ

องค์ประกอบ <ContactsAccountType> จะควบคุมการโต้ตอบของ แอปพลิเคชันรายชื่อติดต่อ โดยไวยากรณ์มีดังนี้

<ContactsAccountType
        xmlns:android="http://schemas.android.com/apk/res/android"
        inviteContactActivity="activity_name"
        inviteContactActionLabel="invite_command_text"
        viewContactNotifyService="view_notify_service"
        viewGroupActivity="group_view_activity"
        viewGroupActionLabel="group_action_text"
        viewStreamItemActivity="viewstream_activity_name"
        viewStreamItemPhotoActivity="viewphotostream_activity_name">

อยู่ใน:

res/xml/contacts.xml

สามารถมีสิ่งต่อไปนี้

<ContactsDataKind>

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

แอตทริบิวต์

android:mimeType
ประเภท MIME ที่กําหนดเองซึ่งคุณกําหนดไว้สําหรับประเภทแถวข้อมูลที่กำหนดเองประเภทใดประเภทหนึ่งในตาราง ContactsContract.Data เช่น ค่า vnd.android.cursor.item/vnd.example.locationstatus อาจเป็นประเภท MIME ที่กําหนดเองสําหรับแถวข้อมูลที่บันทึกตําแหน่งสุดท้ายที่ทราบของรายชื่อติดต่อ
android:icon
ทรัพยากรที่วาดได้ของ Android ที่แสดงข้างข้อมูลของคุณในแอปพลิเคชันรายชื่อติดต่อ ใช้แอตทริบิวต์นี้เพื่อบ่งบอกให้ผู้ใช้ทราบว่าข้อมูลมาจากบริการของคุณ
android:summaryColumn
ชื่อคอลัมน์สำหรับค่าแรกจาก 2 ค่าซึ่งดึงมาจากแถวข้อมูล ค่าจะแสดงเป็นบรรทัดแรกของรายการสําหรับแถวข้อมูลนี้ บรรทัดแรกมีไว้เพื่อใช้เป็นข้อมูลสรุป แต่คุณก็ใช้หรือไม่ใช้ก็ได้ ดูandroid:detailColumn ด้วย
android:detailColumn
ชื่อคอลัมน์ของค่าที่ 2 จาก 2 ค่าที่ดึงมาจากแถวข้อมูล ค่าจะแสดงเป็นบรรทัดที่สองของรายการสำหรับแถวข้อมูลนี้ ดูเพิ่มเติม android:summaryColumn

ฟีเจอร์เพิ่มเติมของผู้ให้บริการรายชื่อติดต่อ

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

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

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

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

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

ข้อมูลสตรีมโซเชียลของบุคคลหนึ่งอาจรวมถึงรูปภาพด้วย โดยข้อมูลเหล่านี้จะจัดเก็บไว้ใน android.provider.ContactsContract.StreamItemPhotos ซึ่งมีอธิบายไว้ใน รายละเอียดในส่วนรูปภาพสตรีมบนโซเชียล