Contacts Provider เป็นคอมโพเนนต์ Android ที่มีประสิทธิภาพและยืดหยุ่นซึ่งจัดการที่เก็บข้อมูลส่วนกลางของอุปกรณ์เกี่ยวกับผู้คน Contacts Provider คือแหล่งข้อมูลที่คุณเห็นในแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ และคุณยังเข้าถึงข้อมูลของแอปพลิเคชัน และโอนข้อมูลระหว่างอุปกรณ์กับบริการออนไลน์ได้ด้วย ผู้ให้บริการรองรับ แหล่งข้อมูลที่หลากหลายและพยายามจัดการข้อมูลให้ได้มากที่สุดสำหรับแต่ละบุคคล จึงทำให้องค์กรมีความซับซ้อน ด้วยเหตุนี้ API ของผู้ให้บริการจึงมีชุดคลาสและอินเทอร์เฟซของสัญญาที่ครอบคลุม ซึ่งช่วยให้ทั้งการดึงข้อมูลและการแก้ไขข้อมูลเป็นไปอย่างราบรื่น
คู่มือนี้อธิบายสิ่งต่อไปนี้
- โครงสร้างพื้นฐานของผู้ให้บริการ
- วิธีกู้คืนข้อมูลจากผู้ให้บริการ
- วิธีแก้ไขข้อมูลในผู้ให้บริการ
- วิธีเขียนอะแดปเตอร์การซิงค์สำหรับซิงค์ข้อมูลจากเซิร์ฟเวอร์ไปยัง Contacts Provider
คู่มือนี้ถือว่าคุณทราบข้อมูลพื้นฐานเกี่ยวกับ Content Provider ของ Android ดูข้อมูลเพิ่มเติม เกี่ยวกับ Content Provider ของ Android ได้ใน คู่มือพื้นฐานของ Content Provider
องค์กร Contacts Provider
Contacts Provider เป็นคอมโพเนนต์ผู้ให้บริการเนื้อหาของ Android โดยจะเก็บข้อมูล 3 ประเภทเกี่ยวกับบุคคล ซึ่งแต่ละประเภทจะสอดคล้องกับตารางที่ผู้ให้บริการเสนอ ดังที่แสดงในรูปที่ 1
รูปที่ 1 โครงสร้างตาราง Contacts Provider
โดยทั่วไปแล้วตารางทั้ง 3 จะอ้างอิงตามชื่อของคลาสสัญญา คลาส กำหนดค่าคงที่สำหรับ URI ของเนื้อหา ชื่อคอลัมน์ และค่าคอลัมน์ที่ใช้โดยตารางต่อไปนี้
-
ContactsContract.Contactsตาราง - แถวที่แสดงบุคคลต่างๆ โดยอิงตามการรวบรวมแถวข้อมูลติดต่อดิบ
-
ContactsContract.RawContactsตาราง - แถวที่มีข้อมูลสรุปของบุคคลหนึ่งๆ ซึ่งเฉพาะเจาะจงกับบัญชีผู้ใช้และประเภท
-
ContactsContract.Dataตาราง - แถวที่มีรายละเอียดสำหรับข้อมูลติดต่อดิบ เช่น อีเมลหรือหมายเลขโทรศัพท์
ตารางอื่นๆ ที่แสดงโดยคลาสสัญญาใน 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
|
แฟล็ก "ลบแล้ว" สำหรับข้อมูลติดต่อดิบ | โดยค่าสถานะนี้จะช่วยให้ 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.comemilyd@gmail.com- บัญชี Twitter "belle_of_amherst"
ผู้ใช้รายนี้ได้เปิดใช้ซิงค์รายชื่อติดต่อสำหรับบัญชีทั้ง 3 บัญชีนี้ในการตั้งค่าบัญชี
สมมติว่าเอมิลี ดิกคินสันเปิดหน้าต่างเบราว์เซอร์ ลงชื่อเข้าใช้ Gmail ในชื่อ
emily.dickinson@gmail.com เปิด
รายชื่อติดต่อ และเพิ่ม "Thomas Higginson" ต่อมาเธอเข้าสู่ระบบ Gmail ในชื่อ
emilyd@gmail.com และส่งอีเมลถึง "Thomas Higginson" ซึ่งระบบจะเพิ่ม
เขาเป็นรายชื่อติดต่อโดยอัตโนมัติ นอกจากนี้ เธอยังติดตาม "colonel_tom" (รหัส Twitter ของ Thomas Higginson) บน
Twitter ด้วย
Contacts Provider จะสร้างรายชื่อติดต่อดิบ 3 รายการจากงานนี้
-
ข้อมูลติดต่อดิบสำหรับ "Thomas Higginson" ที่เชื่อมโยงกับ
emily.dickinson@gmail.comประเภทบัญชีผู้ใช้คือ Google -
ข้อมูลติดต่อดิบที่ 2 สำหรับ "Thomas Higginson" ที่เชื่อมโยงกับ
emilyd@gmail.comประเภทบัญชีผู้ใช้คือ Google มีข้อมูลติดต่อดิบรายการที่ 2 แม้ว่าชื่อจะเหมือนกับชื่อก่อนหน้าก็ตาม เนื่องจากมีการเพิ่มบุคคลดังกล่าวสำหรับบัญชีผู้ใช้ที่แตกต่างกัน - ข้อมูลติดต่อดิบที่ 3 สำหรับ "Thomas Higginson" ที่เชื่อมโยงกับ "belle_of_amherst" ประเภทบัญชีผู้ใช้คือ Twitter
ข้อมูล
ดังที่ได้กล่าวไว้ก่อนหน้านี้ ข้อมูลสำหรับข้อมูลติดต่อดิบจะจัดเก็บไว้ใน
แถว ContactsContract.Data ที่ลิงก์กับค่า _ID ของข้อมูลติดต่อดิบ ซึ่งช่วยให้ผู้ติดต่อดิบรายเดียวมีข้อมูลประเภทเดียวกันได้หลายรายการ เช่น อีเมลหรือหมายเลขโทรศัพท์ ตัวอย่างเช่น หาก
"Thomas Higginson" สำหรับ emilyd@gmail.com (แถวรายชื่อติดต่อดิบสำหรับ Thomas Higginson
ที่เชื่อมโยงกับบัญชี Google emilyd@gmail.com) มีอีเมลส่วนตัวเป็น
thigg@gmail.com และอีเมลที่ทำงานเป็น
thomas.higginson@gmail.com ผู้ให้บริการรายชื่อติดต่อจะจัดเก็บแถวอีเมล 2 แถว
และลิงก์ทั้ง 2 แถวกับรายชื่อติดต่อดิบ
โปรดสังเกตว่าข้อมูลประเภทต่างๆ จะจัดเก็บอยู่ในตารางเดียวนี้ แถวชื่อที่แสดง
หมายเลขโทรศัพท์ อีเมล ที่อยู่ไปรษณีย์ รูปภาพ และรายละเอียดเว็บไซต์ทั้งหมดจะอยู่ในตาราง
ContactsContract.Data เพื่อช่วยจัดการเรื่องนี้ ContactsContract.Data ตารางมีคอลัมน์บางส่วนที่มีชื่อสื่อความหมาย
และคอลัมน์อื่นๆ ที่มีชื่อทั่วไป เนื้อหาของคอลัมน์ชื่อที่สื่อความหมายจะมีค่าเหมือนกัน
ไม่ว่าจะเป็นข้อมูลประเภทใดในแถว ในขณะที่เนื้อหาของคอลัมน์ชื่อทั่วไปจะมี
ความหมายแตกต่างกันไปตามประเภทของข้อมูล
ชื่อคอลัมน์ที่สื่อความหมาย
ตัวอย่างชื่อคอลัมน์ที่สื่อความหมายมีดังนี้
-
RAW_CONTACT_ID -
ค่าของคอลัมน์
_IDของข้อมูลติดต่อดิบสำหรับข้อมูลนี้ -
MIMETYPE -
ประเภทของข้อมูลที่จัดเก็บในแถวนี้ ซึ่งแสดงเป็นประเภท MIME ที่กำหนดเอง Contacts Provider
ใช้ประเภท MIME ที่กำหนดไว้ในคลาสย่อยของ
ContactsContract.CommonDataKindsMIME ประเภทเหล่านี้เป็นโอเพนซอร์ส และแอปพลิเคชันหรืออะแดปเตอร์การซิงค์ใดก็ได้ที่ใช้ได้กับ 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 จะจัดการการสร้างแถวรายชื่อติดต่อใหม่ และการรวบรวมข้อมูลติดต่อดิบกับแถวรายชื่อติดต่อที่มีอยู่ ทั้งแอปพลิเคชันและ ตัวปรับการซิงค์ไม่ได้รับอนุญาตให้เพิ่มรายชื่อติดต่อ และคอลัมน์บางคอลัมน์ในแถวรายชื่อติดต่อเป็นแบบอ่านอย่างเดียว
หมายเหตุ: หากพยายามเพิ่มรายชื่อติดต่อลงในผู้ให้บริการรายชื่อติดต่อด้วย
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) ขึ้นไป โปรดทราบว่าชุดฟิลด์ข้อมูลรายชื่อติดต่อและวิธีการบางอย่างจะเลิกใช้งานแล้ว
ภายใต้เงื่อนไขที่กล่าวถึง ระบบจะล้างค่าที่เขียนลงในฟิลด์ข้อมูลต่อไปนี้เป็นระยะๆ
-
ContactsContract.ContactOptionsColumns.LAST_TIME_CONTACTED -
ContactsContract.ContactOptionsColumns.TIMES_CONTACTED -
ContactsContract.DataUsageStatColumns.LAST_TIME_USED -
ContactsContract.DataUsageStatColumns.TIMES_USED
API ที่ใช้ในการตั้งค่าฟิลด์ข้อมูลข้างต้นจะเลิกใช้งานด้วยเช่นกัน
นอกจากนี้ ฟิลด์ต่อไปนี้จะไม่แสดงรายชื่อที่ติดต่อบ่อยอีกต่อไป โปรดทราบ ว่าฟิลด์บางรายการเหล่านี้จะส่งผลต่อการจัดอันดับรายชื่อติดต่อก็ต่อเมื่อรายชื่อติดต่อ เป็นส่วนหนึ่งของข้อมูล ประเภทที่เฉพาะเจาะจง
-
ContactsContract.Contacts.CONTENT_FREQUENT_URI -
ContactsContract.Contacts.CONTENT_STREQUENT_URI -
ContactsContract.Contacts.CONTENT_STREQUENT_FILTER_URI -
CONTENT_FILTER_URI(มีผลเฉพาะ อีเมล โทรศัพท์ โทรได้ และ ติดต่อได้ ประเภทข้อมูล) -
ENTERPRISE_CONTENT_FILTER_URI(มีผลเฉพาะ อีเมล โทรศัพท์ และ โทรได้ ประเภทข้อมูล)
หากแอปของคุณเข้าถึงหรืออัปเดตฟิลด์หรือ API เหล่านี้ ให้ใช้วิธีอื่น ตัวอย่างเช่น คุณสามารถตอบสนอง Use Case บางอย่างได้โดยใช้ Content Provider แบบส่วนตัวหรือข้อมูลอื่นๆ ที่จัดเก็บไว้ในแอปหรือระบบแบ็กเอนด์ ของคุณ
หากต้องการยืนยันว่าฟังก์ชันการทำงานของแอปไม่ได้รับผลกระทบจากการเปลี่ยนแปลงนี้ คุณ สามารถล้างช่องข้อมูลเหล่านี้ด้วยตนเองได้ โดยให้เรียกใช้คำสั่ง adb ต่อไปนี้ในอุปกรณ์ที่ใช้ Android 4.1 (ระดับ API 16) ขึ้นไป
adb shell content delete \ --uri content://com.android.contacts/contacts/delete_usage
ข้อมูลจากอะแดปเตอร์การซิงค์
ผู้ใช้จะป้อนข้อมูลรายชื่อติดต่อลงในอุปกรณ์โดยตรง แต่ข้อมูลจะไหลเข้าสู่ Contacts
Provider จากบริการบนเว็บผ่านตัวปรับการซิงค์ ซึ่งจะทำให้การโอนข้อมูลระหว่างอุปกรณ์กับบริการเป็นไปโดยอัตโนมัติ
Sync Adapter จะทำงานในเบื้องหลัง
ภายใต้การควบคุมของระบบ และจะเรียกใช้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 อยู่ในขั้นตอนการไหลของข้อมูล เกี่ยวกับผู้คนอย่างไร ในช่องที่ทำเครื่องหมาย "อะแดปเตอร์การซิงค์" อะแดปเตอร์แต่ละตัวจะมีป้ายกำกับตามประเภทบัญชี
รูปที่ 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 อัปเดตแถว
อะแดปเตอร์การซิงค์ที่แก้ไขตารางข้อมูลหรือข้อมูลติดต่อดิบควรต่อท้ายสตริง |
| "1" - มีการเปลี่ยนแปลงตั้งแต่การซิงค์ครั้งล่าสุด ต้องซิงค์กลับไปยังเซิร์ฟเวอร์ | |||
ContactsContract.RawContacts |
VERSION |
หมายเลขเวอร์ชันของแถวนี้ | Contacts Provider จะเพิ่มค่านี้โดยอัตโนมัติเมื่อใดก็ตามที่แถวหรือ ข้อมูลที่เกี่ยวข้องมีการเปลี่ยนแปลง |
ContactsContract.Data |
DATA_VERSION |
หมายเลขเวอร์ชันของแถวนี้ | Contacts Provider จะเพิ่มค่านี้โดยอัตโนมัติทุกครั้งที่มีการเปลี่ยนแปลงแถวข้อมูล |
ContactsContract.RawContacts |
SOURCE_ID |
ค่าสตริงที่ระบุข้อมูลติดต่อดิบนี้ในบัญชีที่สร้างขึ้นอย่างไม่ซ้ำกัน |
เมื่ออะแดปเตอร์การซิงค์สร้างข้อมูลติดต่อดิบใหม่ คอลัมน์นี้ควรตั้งค่าเป็น
รหัสที่ไม่ซ้ำกันของเซิร์ฟเวอร์สำหรับข้อมูลติดต่อดิบ เมื่อแอปพลิเคชัน Android สร้าง
ข้อมูลติดต่อดิบใหม่ แอปพลิเคชันควรปล่อยให้คอลัมน์นี้ว่างไว้ ซึ่งจะส่งสัญญาณไปยังอะแดปเตอร์การซิงค์
ว่าควรสร้างข้อมูลติดต่อดิบใหม่ในเซิร์ฟเวอร์ และรับค่าสำหรับ SOURCE_ID
โดยเฉพาะอย่างยิ่ง รหัสแหล่งที่มาต้องไม่ซ้ำกันสำหรับบัญชีแต่ละประเภท และควรคงที่ตลอดการซิงค์
|
ContactsContract.Groups |
GROUP_VISIBLE |
"0" - รายชื่อติดต่อในกลุ่มนี้ไม่ควรปรากฏใน UI ของแอปพลิเคชัน Android | คอลัมน์นี้ใช้เพื่อความเข้ากันได้กับเซิร์ฟเวอร์ที่อนุญาตให้ผู้ใช้ซ่อนรายชื่อติดต่อใน บางกลุ่ม |
| "1" - อนุญาตให้รายชื่อติดต่อในกลุ่มนี้ปรากฏใน UI ของแอปพลิเคชัน | |||
ContactsContract.Settings |
UNGROUPED_VISIBLE |
"0" - สำหรับบัญชีและประเภทบัญชีนี้ รายชื่อติดต่อที่ไม่ได้อยู่ในกลุ่มจะ ไม่ปรากฏใน UI ของแอปพลิเคชัน Android |
โดยค่าเริ่มต้น รายชื่อติดต่อจะมองไม่เห็นหากไม่มีข้อมูลติดต่อดิบอยู่ในกลุ่ม
(การเป็นสมาชิกกลุ่มสำหรับข้อมูลติดต่อดิบจะระบุด้วยแถวอย่างน้อย 1 แถว
ContactsContract.CommonDataKinds.GroupMembership
ในตาราง ContactsContract.Data)
การตั้งค่าสถานะนี้ในContactsContract.Settingsแถวตาราง
สำหรับประเภทบัญชีและบัญชีจะทำให้รายชื่อติดต่อที่ไม่มีกลุ่มแสดงได้
การใช้แฟล็กนี้อย่างหนึ่งคือการแสดงรายชื่อติดต่อจากเซิร์ฟเวอร์ที่ไม่ได้ใช้กลุ่ม
|
| "1" - สำหรับบัญชีและประเภทบัญชีนี้ รายชื่อติดต่อที่ไม่ได้อยู่ในกลุ่มจะ มองเห็นได้ใน UI ของแอปพลิเคชัน | |||
ContactsContract.SyncState |
(ทั้งหมด) | ใช้ตารางนี้เพื่อจัดเก็บข้อมูลเมตาสำหรับอะแดปเตอร์การซิงค์ | ตารางนี้ช่วยให้คุณจัดเก็บสถานะการซิงค์และข้อมูลอื่นๆ ที่เกี่ยวข้องกับการซิงค์อย่างถาวรในอุปกรณ์ได้ |
การเข้าถึง Contacts Provider
ส่วนนี้จะอธิบายหลักเกณฑ์ในการเข้าถึงข้อมูลจาก 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 เมื่อผู้ให้บริการรายชื่อติดต่อพบจุดที่ต้องหยุดชั่วคราว ผู้ให้บริการจะหยุดการทำงานเพื่อ
ให้กระบวนการอื่นๆ ทำงานและปิดธุรกรรมปัจจุบัน เมื่อผู้ให้บริการเริ่มทำงานอีกครั้ง ผู้ให้บริการจะดำเนินการต่อด้วยการดำเนินการถัดไปใน ArrayList และเริ่มธุรกรรมใหม่
คะแนนผลตอบแทนจะส่งผลให้มีการทำธุรกรรมมากกว่า 1 รายการต่อการเรียกใช้
applyBatch() ด้วยเหตุนี้ คุณจึงควรกำหนดจุดหยุดชั่วคราวสำหรับการดำเนินการสุดท้ายของชุดแถวที่เกี่ยวข้อง
เช่น คุณควรตั้งค่าจุดหยุดชั่วคราวสำหรับการดำเนินการสุดท้ายในชุดที่เพิ่ม
ข้อมูลติดต่อดิบและแถวข้อมูลที่เกี่ยวข้อง หรือการดำเนินการสุดท้ายสำหรับชุดแถวที่เกี่ยวข้อง
กับรายชื่อติดต่อเดียว
นอกจากนี้ จุดผลตอบแทนยังเป็นหน่วยของการดำเนินการแบบอะตอมมิกด้วย การเข้าถึงทั้งหมดระหว่างจุดที่ให้ผลตอบแทน 2 จุดจะ สำเร็จหรือล้มเหลวเป็นหน่วยเดียว หากไม่ได้ตั้งค่าจุดให้ผล การดำเนินการย่อยที่เล็กที่สุด คือชุดการดำเนินการทั้งหมด หากใช้จุดผลตอบแทน คุณจะป้องกันไม่ให้การดำเนินการ ทำให้ประสิทธิภาพของระบบลดลง ในขณะเดียวกันก็มั่นใจได้ว่าการดำเนินการ บางส่วนจะเป็นแบบอะตอม
การอ้างอิงย้อนกลับของการแก้ไข
เมื่อแทรกแถวรายชื่อติดต่อดิบใหม่และแถวข้อมูลที่เกี่ยวข้องเป็นชุดของออบเจ็กต์ ContentProviderOperation คุณต้องลิงก์แถวข้อมูลกับแถวรายชื่อติดต่อดิบโดยการแทรกค่า _ID ของรายชื่อติดต่อดิบเป็นค่า RAW_CONTACT_ID อย่างไรก็ตาม ค่านี้จะไม่พร้อมใช้งานเมื่อคุณสร้าง ContentProviderOperation
สำหรับแถวข้อมูล เนื่องจากคุณยังไม่ได้ใช้
ContentProviderOperation สำหรับแถวข้อมูลติดต่อดิบ หากต้องการหลีกเลี่ยงปัญหานี้
ContentProviderOperation.Builder คลาสมีเมธอด
withValueBackReference()
วิธีนี้ช่วยให้คุณแทรกหรือแก้ไขคอลัมน์ที่มี
ผลลัพธ์ของการดำเนินการก่อนหน้าได้
เมธอด withValueBackReference()
มีอาร์กิวเมนต์ 2 รายการ ดังนี้
-
key - คีย์ของคู่คีย์-ค่า ค่าของอาร์กิวเมนต์นี้ควรเป็นชื่อของคอลัมน์ ในตารางที่คุณกำลังแก้ไข
-
previousResult -
ดัชนีแบบ 0 ของค่าในอาร์เรย์ของออบเจ็กต์
ContentProviderResultจากapplyBatch()เมื่อ ใช้การดำเนินการแบบกลุ่ม ระบบจะจัดเก็บผลลัพธ์ของการดำเนินการแต่ละรายการไว้ใน อาร์เรย์ผลลัพธ์ชั่วคราว ค่าpreviousResultคือดัชนี ของผลลัพธ์อย่างใดอย่างหนึ่งต่อไปนี้ ซึ่งจะได้รับการดึงข้อมูลและจัดเก็บพร้อมกับค่าkeyซึ่งจะช่วยให้คุณแทรกระเบียนข้อมูลติดต่อดิบใหม่และรับค่า_IDจากนั้นสร้าง "การอ้างอิงย้อนกลับ" ไปยังค่า เมื่อเพิ่มแถวContactsContract.Dataอาร์เรย์ผลลัพธ์ทั้งหมดจะสร้างขึ้นเมื่อคุณเรียกใช้
applyBatch(), เป็นครั้งแรก โดยมีขนาดเท่ากับขนาดของArrayListของออบเจ็กต์ContentProviderOperationที่คุณระบุ อย่างไรก็ตาม องค์ประกอบทั้งหมดในอาร์เรย์ผลลัพธ์จะตั้งค่าเป็นnullและหากคุณพยายาม อ้างอิงย้อนกลับไปยังผลลัพธ์สำหรับการดำเนินการที่ยังไม่ได้ใช้withValueBackReference()จะส่งException
ข้อมูลโค้ดต่อไปนี้แสดงวิธีแทรกข้อมูลติดต่อดิบและข้อมูลใหม่ในกลุ่ม โดยมีโค้ดที่กำหนดจุดหยุดชั่วคราวและใช้การอ้างอิงย้อนกลับ
ข้อมูลโค้ดแรกจะดึงข้อมูลรายชื่อติดต่อจาก UI ในขั้นตอนนี้ ผู้ใช้ได้เลือกบัญชีที่จะเพิ่มข้อมูลติดต่อดิบใหม่แล้ว
Kotlin
// Creates a contact entry from the current UI values, using the currently-selected account. private fun createContactEntry() { /* * Gets values from the UI */ val name = contactNameEditText.text.toString() val phone = contactPhoneEditText.text.toString() val email = contactEmailEditText.text.toString() val phoneType: String = contactPhoneTypes[mContactPhoneTypeSpinner.selectedItemPosition] val emailType: String = contactEmailTypes[mContactEmailTypeSpinner.selectedItemPosition]
Java
// Creates a contact entry from the current UI values, using the currently-selected account. protected void createContactEntry() { /* * Gets values from the UI */ String name = contactNameEditText.getText().toString(); String phone = contactPhoneEditText.getText().toString(); String email = contactEmailEditText.getText().toString(); int phoneType = contactPhoneTypes.get( contactPhoneTypeSpinner.getSelectedItemPosition()); int emailType = contactEmailTypes.get( contactEmailTypeSpinner.getSelectedItemPosition());
ข้อมูลโค้ดถัดไปจะสร้างการดำเนินการเพื่อแทรกแถวข้อมูลติดต่อดิบลงในตาราง
ContactsContract.RawContacts
Kotlin
/* * Prepares the batch operation for inserting a new raw contact and its data. Even if * the Contacts Provider does not have any data for this person, you can't add a Contact, * only a raw contact. The Contacts Provider will then add a Contact automatically. */ // Creates a new array of ContentProviderOperation objects. val ops = arrayListOf<ContentProviderOperation>() /* * Creates a new raw contact with its account type (server type) and account name * (user's account). Remember that the display name is not stored in this row, but in a * StructuredName data row. No other data is required. */ var op: ContentProviderOperation.Builder = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.name) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.type) // Builds the operation and adds it to the array of operations ops.add(op.build())
Java
/* * Prepares the batch operation for inserting a new raw contact and its data. Even if * the Contacts Provider does not have any data for this person, you can't add a Contact, * only a raw contact. The Contacts Provider will then add a Contact automatically. */ // Creates a new array of ContentProviderOperation objects. ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); /* * Creates a new raw contact with its account type (server type) and account name * (user's account). Remember that the display name is not stored in this row, but in a * StructuredName data row. No other data is required. */ ContentProviderOperation.Builder op = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.getType()) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.getName()); // Builds the operation and adds it to the array of operations ops.add(op.build());
จากนั้นโค้ดจะสร้างแถวข้อมูลสำหรับแถวชื่อที่แสดง โทรศัพท์ และอีเมล
ออบเจ็กต์เครื่องมือสร้างการดำเนินการแต่ละรายการใช้
withValueBackReference()
เพื่อรับ
RAW_CONTACT_ID จุดอ้างอิง
กลับไปยังออบเจ็กต์ ContentProviderResult จากการดำเนินการแรก
ซึ่งจะเพิ่มแถวข้อมูลติดต่อดิบและแสดงผลค่า _ID
ใหม่ ด้วยเหตุนี้ ระบบจึงลิงก์แถวข้อมูลแต่ละแถวโดยอัตโนมัติด้วย
RAW_CONTACT_ID
ไปยังแถว ContactsContract.RawContacts ใหม่ที่แถวนั้นเป็นของ
ออบเจ็กต์ ContentProviderOperation.Builder ที่เพิ่มแถวอีเมลจะมีการแจ้งว่า withYieldAllowed() ซึ่งจะตั้งค่าจุดหยุดชั่วคราว
Kotlin
// Creates the display name for the new raw contact, as a StructuredName data row. op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * withValueBackReference sets the value of the first argument to the value of * the ContentProviderResult indexed by the second argument. In this particular * call, the raw contact ID column of the StructuredName data row is set to the * value of the result returned by the first operation, which is the one that * actually adds the raw contact row. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to StructuredName .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) // Sets the data row's display name to the name in the UI. .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name) // Builds the operation and adds it to the array of operations ops.add(op.build()) // Inserts the specified phone number and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Phone .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Sets the phone number and type .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType) // Builds the operation and adds it to the array of operations ops.add(op.build()) // Inserts the specified email and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Email .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Sets the email address and type .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType) /* * Demonstrates a yield point. At the end of this insert, the batch operation's thread * will yield priority to other threads. Use after every set of operations that affect a * single contact, to avoid degrading performance. */ op.withYieldAllowed(true) // Builds the operation and adds it to the array of operations ops.add(op.build())
Java
// Creates the display name for the new raw contact, as a StructuredName data row. op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * withValueBackReference sets the value of the first argument to the value of * the ContentProviderResult indexed by the second argument. In this particular * call, the raw contact ID column of the StructuredName data row is set to the * value of the result returned by the first operation, which is the one that * actually adds the raw contact row. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to StructuredName .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) // Sets the data row's display name to the name in the UI. .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name); // Builds the operation and adds it to the array of operations ops.add(op.build()); // Inserts the specified phone number and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Phone .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Sets the phone number and type .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType); // Builds the operation and adds it to the array of operations ops.add(op.build()); // Inserts the specified email and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Email .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Sets the email address and type .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType); /* * Demonstrates a yield point. At the end of this insert, the batch operation's thread * will yield priority to other threads. Use after every set of operations that affect a * single contact, to avoid degrading performance. */ op.withYieldAllowed(true); // Builds the operation and adds it to the array of operations ops.add(op.build());
ข้อมูลโค้ดสุดท้ายแสดงการเรียกใช้
applyBatch() ที่
แทรกข้อมูลติดต่อดิบและแถวข้อมูลใหม่
Kotlin
// Ask the Contacts Provider to create a new contact Log.d(TAG, "Selected account: ${mSelectedAccount.name} (${mSelectedAccount.type})") Log.d(TAG, "Creating contact: $name") /* * Applies the array of ContentProviderOperation objects in batch. The results are * discarded. */ try { contentResolver.applyBatch(ContactsContract.AUTHORITY, ops) } catch (e: Exception) { // Display a warning val txt: String = getString(R.string.contactCreationFailure) Toast.makeText(applicationContext, txt, Toast.LENGTH_SHORT).show() // Log exception Log.e(TAG, "Exception encountered while inserting contact: $e") } }
Java
// Ask the Contacts Provider to create a new contact Log.d(TAG,"Selected account: " + selectedAccount.getName() + " (" + selectedAccount.getType() + ")"); Log.d(TAG,"Creating contact: " + name); /* * Applies the array of ContentProviderOperation objects in batch. The results are * discarded. */ try { getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); } catch (Exception e) { // Display a warning Context ctx = getApplicationContext(); CharSequence txt = getString(R.string.contactCreationFailure); int duration = Toast.LENGTH_SHORT; Toast toast = Toast.makeText(ctx, txt, duration); toast.show(); // Log exception Log.e(TAG, "Exception encountered while inserting contact: " + e); } }
การดำเนินการแบบกลุ่มยังช่วยให้คุณใช้การควบคุมการเกิดขึ้นพร้อมกันแบบมองโลกในแง่ดีได้ด้วย ซึ่งเป็นวิธีการใช้ธุรกรรมการแก้ไขโดยไม่ต้องล็อกที่เก็บข้อมูลพื้นฐาน หากต้องการใช้วิธีนี้ ให้ใช้ธุรกรรม แล้วตรวจสอบการแก้ไขอื่นๆ ที่อาจเกิดขึ้นพร้อมกัน หากพบว่ามีการแก้ไขที่ไม่สอดคล้องกันเกิดขึ้น คุณ สามารถย้อนกลับธุรกรรมและลองอีกครั้ง
การควบคุมการเกิดขึ้นพร้อมกันแบบมองโลกในแง่ดีมีประโยชน์สำหรับอุปกรณ์เคลื่อนที่ ซึ่งมีผู้ใช้เพียงคนเดียวในแต่ละครั้ง และการเข้าถึงที่เก็บข้อมูลพร้อมกันนั้นเกิดขึ้นได้ยาก เนื่องจากไม่ได้ใช้การล็อก จึงไม่ต้องเสียเวลาในการตั้งค่าการล็อกหรือรอให้ธุรกรรมอื่นๆ ปลดล็อก
หากต้องการใช้การควบคุมการเกิดขึ้นพร้อมกันแบบมองโลกในแง่ดีขณะอัปเดตแถวเดียว
ContactsContract.RawContacts ให้ทำตามขั้นตอนต่อไปนี้
-
เรียกข้อมูลคอลัมน์
VERSIONของรายชื่อติดต่อดิบพร้อมกับข้อมูลอื่นๆ ที่คุณเรียก -
สร้างออบเจ็กต์
ContentProviderOperation.Builderที่เหมาะสำหรับ การบังคับใช้ข้อจำกัดโดยใช้วิธีการnewAssertQuery(Uri)สำหรับ URI เนื้อหา ให้ใช้RawContacts.CONTENT_URIโดยต่อท้ายด้วย_IDของข้อมูลติดต่อดิบ -
สำหรับออบเจ็กต์
ContentProviderOperation.Builderให้เรียกใช้withValue()เพื่อเปรียบเทียบคอลัมน์VERSIONกับหมายเลขเวอร์ชันที่คุณเพิ่งดึงข้อมูลมา -
สำหรับ
ContentProviderOperation.Builderเดียวกัน ให้เรียกใช้withExpectedCount()เพื่อให้แน่ใจว่าการยืนยันนี้จะทดสอบเพียงแถวเดียว -
เรียกใช้
build()เพื่อสร้างออบเจ็กต์ContentProviderOperationจากนั้นเพิ่มออบเจ็กต์นี้เป็นออบเจ็กต์แรกในArrayListที่คุณส่งไปยังapplyBatch() - ใช้ธุรกรรมแบบกลุ่ม
หากมีการอัปเดตแถวของข้อมูลติดต่อดิบโดยการดำเนินการอื่นระหว่างเวลาที่คุณอ่านแถวกับ
เวลาที่คุณพยายามแก้ไข "ยืนยัน" ContentProviderOperation
จะล้มเหลว และระบบจะยกเลิกการดำเนินการทั้งหมดในชุด จากนั้นคุณสามารถเลือกที่จะลองอีกครั้ง
กับกลุ่มหรือการดำเนินการอื่นๆ
ข้อมูลโค้ดต่อไปนี้แสดงวิธีสร้าง "assert"
ContentProviderOperation หลังจากค้นหาข้อมูลติดต่อดิบรายการเดียวโดยใช้
CursorLoader
Kotlin
/* * The application uses CursorLoader to query the raw contacts table. The system calls this method * when the load is finished. */ override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) { // Gets the raw contact's _ID and VERSION values rawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID)) mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION)) } ... // Sets up a Uri for the assert operation val rawContactUri: Uri = ContentUris.withAppendedId( ContactsContract.RawContacts.CONTENT_URI, rawContactID ) // Creates a builder for the assert operation val assertOp: ContentProviderOperation.Builder = ContentProviderOperation.newAssertQuery(rawContactUri).apply { // Adds the assertions to the assert operation: checks the version withValue(SyncColumns.VERSION, mVersion) // and count of rows tested withExpectedCount(1) } // Creates an ArrayList to hold the ContentProviderOperation objects val ops = arrayListOf<ContentProviderOperation>() ops.add(assertOp.build()) // You would add the rest of your batch operations to "ops" here ... // Applies the batch. If the assert fails, an Exception is thrown try { val results: Array<ContentProviderResult> = contentResolver.applyBatch(AUTHORITY, ops) } catch (e: OperationApplicationException) { // Actions you want to take if the assert operation fails go here }
Java
/* * The application uses CursorLoader to query the raw contacts table. The system calls this method * when the load is finished. */ public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { // Gets the raw contact's _ID and VERSION values rawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID)); mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION)); } ... // Sets up a Uri for the assert operation Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactID); // Creates a builder for the assert operation ContentProviderOperation.Builder assertOp = ContentProviderOperation.newAssertQuery(rawContactUri); // Adds the assertions to the assert operation: checks the version and count of rows tested assertOp.withValue(SyncColumns.VERSION, mVersion); assertOp.withExpectedCount(1); // Creates an ArrayList to hold the ContentProviderOperation objects ArrayList ops = new ArrayList<ContentProviderOperation>; ops.add(assertOp.build()); // You would add the rest of your batch operations to "ops" here ... // Applies the batch. If the assert fails, an Exception is thrown try { ContentProviderResult[] results = getContentResolver().applyBatch(AUTHORITY, ops); } catch (OperationApplicationException e) { // Actions you want to take if the assert operation fails go here }
การดึงข้อมูลและการแก้ไขด้วย Intent
การส่ง Intent ไปยังแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์จะช่วยให้คุณเข้าถึง Contacts Provider โดยอ้อมได้ Intent จะเริ่ม UI ของแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ ซึ่งผู้ใช้สามารถ ทำงานที่เกี่ยวข้องกับรายชื่อผู้ติดต่อได้ เมื่อมีสิทธิ์เข้าถึงประเภทนี้ ผู้ใช้จะทำสิ่งต่อไปนี้ได้
- เลือกรายชื่อติดต่อจากรายการและส่งกลับไปยังแอปของคุณเพื่อดำเนินการต่อ
- แก้ไขข้อมูลของผู้ติดต่อที่มีอยู่
- แทรกข้อมูลติดต่อดิบใหม่สำหรับบัญชีใดก็ได้
- ลบรายชื่อติดต่อหรือข้อมูลรายชื่อติดต่อ
หากผู้ใช้แทรกหรืออัปเดตข้อมูล คุณสามารถรวบรวมข้อมูลก่อนแล้วส่งเป็น ส่วนหนึ่งของ Intent ได้
เมื่อใช้ Intent เพื่อเข้าถึง Contacts Provider ผ่านแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ คุณ ไม่จำเป็นต้องเขียน UI หรือโค้ดของคุณเองเพื่อเข้าถึงผู้ให้บริการ นอกจากนี้ คุณยังไม่จำเป็นต้อง ขอสิทธิ์อ่านหรือเขียนไปยังผู้ให้บริการ แอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์สามารถ มอบสิทธิ์อ่านรายชื่อติดต่อให้คุณได้ และเนื่องจากคุณทำการแก้ไขผู้ให้บริการผ่านแอปพลิเคชันอื่น คุณจึงไม่จำเป็นต้องมีสิทธิ์เขียน
กระบวนการทั่วไปในการส่ง Intent เพื่อเข้าถึงผู้ให้บริการอธิบายไว้โดยละเอียดใน
คู่มือข้อมูลเบื้องต้นเกี่ยวกับผู้ให้บริการเนื้อหาในส่วน "การเข้าถึงข้อมูลผ่าน Intent" การดำเนินการ
ประเภท MIME และค่าข้อมูลที่คุณใช้สำหรับงานที่พร้อมใช้งานจะสรุปไว้ในตารางที่ 4 ส่วนค่า
extras ที่คุณใช้กับ
putExtra() จะแสดงอยู่ใน
เอกสารอ้างอิงสำหรับ ContactsContract.Intents.Insert
ตารางที่ 4 เจตนาของ Contacts Provider
| งาน | การทำงาน | ข้อมูล | ประเภท MIME | หมายเหตุ |
|---|---|---|---|---|
| เลือกรายชื่อติดต่อจากรายการ | ACTION_PICK |
ค่าใดค่าหนึ่งต่อไปนี้
|
ไม่ได้ใช้ |
แสดงรายการข้อมูลติดต่อดิบหรือรายการข้อมูลจากข้อมูลติดต่อดิบ ทั้งนี้ขึ้นอยู่กับประเภท URI เนื้อหาที่คุณระบุ
Call
|
| แทรกข้อมูลติดต่อดิบใหม่ | Insert.ACTION |
ไม่มี |
RawContacts.CONTENT_TYPE ประเภท MIME สำหรับชุดรายชื่อติดต่อดิบ
|
แสดงหน้าจอเพิ่มรายชื่อติดต่อของแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ ค่า
extras ที่คุณเพิ่มลงใน Intent จะแสดงขึ้น หากส่งพร้อมกับ
startActivityForResult()
ระบบจะส่ง URI เนื้อหาของข้อมูลติดต่อดิบที่เพิ่มใหม่กลับไปยัง
onActivityResult()
เมธอด 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);
ความสมบูรณ์ของข้อมูล
เนื่องจากที่เก็บรายชื่อติดต่อมีข้อมูลที่สำคัญและละเอียดอ่อนซึ่งผู้ใช้คาดหวังว่าข้อมูลดังกล่าวจะถูกต้องและเป็นปัจจุบัน ผู้ให้บริการรายชื่อติดต่อจึงมีกฎที่กำหนดไว้อย่างชัดเจนสำหรับความสมบูรณ์ของข้อมูล คุณมีหน้าที่รับผิดชอบในการปฏิบัติตามกฎเหล่านี้เมื่อแก้ไขข้อมูลรายชื่อติดต่อ กฎที่สำคัญ มีดังนี้
-
เพิ่ม
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 ที่อะแดปเตอร์การซิงค์ซิงค์ด้วย ในตอนนี้ ระบบจะเริ่มจัดการอแดปเตอร์
และเรียกใช้อแดปเตอร์ตามความจำเป็นเพื่อซิงค์ระหว่างผู้ให้บริการเนื้อหากับเซิร์ฟเวอร์
หมายเหตุ: การใช้ประเภทบัญชีเป็นส่วนหนึ่งของการระบุตัวตนของ Sync Adapter จะช่วยให้ระบบตรวจหาและจัดกลุ่ม Sync Adapter ที่เข้าถึงบริการต่างๆ จากองค์กรเดียวกันได้ เช่น อะแดปเตอร์การซิงค์สำหรับบริการออนไลน์ของ Google ทั้งหมดมี
ประเภทบัญชีcom.googleเดียวกัน เมื่อผู้ใช้เพิ่มบัญชี Google ลงในอุปกรณ์ ระบบจะแสดงอะแดปเตอร์การซิงค์ที่ติดตั้งไว้ทั้งหมดสำหรับบริการของ Google ไว้ด้วยกัน โดยอะแดปเตอร์การซิงค์แต่ละรายการที่แสดงจะซิงค์กับ Content Provider ที่แตกต่างกันในอุปกรณ์
เนื่องจากบริการส่วนใหญ่กำหนดให้ผู้ใช้ต้องยืนยันตัวตนก่อนจึงจะเข้าถึงข้อมูลได้
ระบบ Android จึงมีเฟรมเวิร์กการตรวจสอบสิทธิ์ที่คล้ายกับเฟรมเวิร์กอะแดปเตอร์การซิงค์ และมักใช้ร่วมกับเฟรมเวิร์กอะแดปเตอร์การซิงค์
เฟรมเวิร์กการตรวจสอบสิทธิ์ใช้
เครื่องมือตรวจสอบสิทธิ์แบบปลั๊กอินซึ่งเป็นคลาสย่อยของ
AbstractAccountAuthenticator เครื่องมือตรวจสอบสิทธิ์จะยืนยันตัวตนของผู้ใช้โดยทำตามขั้นตอนต่อไปนี้
- รวบรวมชื่อ รหัสผ่าน หรือข้อมูลที่คล้ายกันของผู้ใช้ (ข้อมูลเข้าสู่ระบบของผู้ใช้)
- ส่งข้อมูลเข้าสู่ระบบไปยังบริการ
- ตรวจสอบการตอบกลับของบริการ
หากบริการยอมรับข้อมูลเข้าสู่ระบบ วิธีการตรวจสอบสิทธิ์จะ
จัดเก็บข้อมูลเข้าสู่ระบบไว้ใช้ในภายหลังได้ เนื่องจากเฟรมเวิร์กของโปรแกรมตรวจสอบสิทธิ์แบบปลั๊กอิน
AccountManager จึงให้สิทธิ์เข้าถึงโทเค็นการตรวจสอบสิทธิ์ใดก็ได้ที่โปรแกรมตรวจสอบสิทธิ์
รองรับและเลือกที่จะเปิดเผย เช่น โทเค็นการตรวจสอบสิทธิ์ OAuth2
แม้ว่าไม่จำเป็นต้องมีการตรวจสอบสิทธิ์ แต่บริการรายชื่อติดต่อส่วนใหญ่ก็ใช้การตรวจสอบสิทธิ์ อย่างไรก็ตาม คุณไม่จำเป็นต้องใช้เฟรมเวิร์กการตรวจสอบสิทธิ์ของ Android เพื่อทำการตรวจสอบสิทธิ์
การใช้งานอะแดปเตอร์การซิงค์
หากต้องการใช้ตัวอะแดปเตอร์การซิงค์สำหรับ Contacts Provider คุณต้องเริ่มต้นด้วยการสร้างแอปพลิเคชัน Android ที่มีองค์ประกอบต่อไปนี้
-
คอมโพเนนต์
Serviceที่ตอบสนองต่อคำขอจากระบบเพื่อ เชื่อมโยงกับอะแดปเตอร์การซิงค์ -
เมื่อระบบต้องการเรียกใช้การซิงค์ ระบบจะเรียกใช้เมธอด
onBind()ของบริการเพื่อรับIBinderสำหรับอะแดปเตอร์การซิงค์ ซึ่งจะช่วยให้ระบบสามารถ โทรข้ามกระบวนการไปยังเมธอดของอแดปเตอร์ได้ -
อะแดปเตอร์การซิงค์จริงที่ใช้เป็นคลาสย่อยที่เฉพาะเจาะจงของ
AbstractThreadedSyncAdapter -
คลาสนี้จะทำหน้าที่ดาวน์โหลดข้อมูลจากเซิร์ฟเวอร์ อัปโหลดข้อมูลจาก
อุปกรณ์ และแก้ไขข้อขัดแย้ง การทำงานหลักของอแดปเตอร์จะ
ดำเนินการในเมธอด
onPerformSync()ต้องสร้างอินสแตนซ์ของคลาสนี้เป็น Singleton -
คลาสย่อยของ
Application -
คลาสนี้ทำหน้าที่เป็นโรงงานสำหรับอะแดปเตอร์การซิงค์แบบ Singleton ใช้วิธี
onCreate()เพื่อสร้างอินสแตนซ์ของอะแดปเตอร์การซิงค์ และ ระบุเมธอด "Getter" แบบคงที่เพื่อส่งคืน Singleton ไปยังเมธอดonBind()ของบริการอะแดปเตอร์การซิงค์ -
ไม่บังคับ:
Serviceคอมโพเนนต์ที่ตอบกลับ คำขอจากระบบสำหรับการตรวจสอบสิทธิ์ผู้ใช้ -
AccountManagerเริ่มบริการนี้เพื่อเริ่มกระบวนการ ตรวจสอบสิทธิ์ เมธอดonCreate()ของบริการจะสร้างออบเจ็กต์ Authenticator เมื่อระบบต้องการตรวจสอบสิทธิ์บัญชีผู้ใช้สำหรับ อะแดปเตอร์การซิงค์ ของแอปพลิเคชัน ระบบจะเรียกใช้เมธอดonBind()ของบริการเพื่อรับIBinderสำหรับ Authenticator ซึ่งจะช่วยให้ระบบ โทรข้ามกระบวนการไปยังเมธอดของเครื่องมือตรวจสอบสิทธิ์ได้ -
ไม่บังคับ: คลาสย่อยที่เฉพาะเจาะจงของ
AbstractAccountAuthenticatorซึ่งจัดการคำขอสำหรับ การตรวจสอบสิทธิ์ -
คลาสนี้มีเมธอดที่
AccountManagerเรียกใช้ เพื่อตรวจสอบสิทธิ์ข้อมูลเข้าสู่ระบบของผู้ใช้กับเซิร์ฟเวอร์ รายละเอียดของ กระบวนการตรวจสอบสิทธิ์จะแตกต่างกันไปตามเทคโนโลยีเซิร์ฟเวอร์ที่ใช้ คุณควร ดูเอกสารประกอบสำหรับซอฟต์แวร์เซิร์ฟเวอร์เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับการตรวจสอบสิทธิ์ - ไฟล์ XML ที่กำหนดอะแดปเตอร์การซิงค์และเครื่องมือตรวจสอบสิทธิ์ให้กับระบบ
-
คอมโพเนนต์บริการ Authenticator และอะแดปเตอร์การซิงค์ที่อธิบายไว้ก่อนหน้านี้จะ
กำหนดไว้ใน
<service>ในไฟล์ Manifest ของแอปพลิเคชัน องค์ประกอบเหล่านี้ มีองค์ประกอบย่อย<meta-data>ซึ่งให้ข้อมูลที่เฉพาะเจาะจงแก่ระบบ-
องค์ประกอบ
<meta-data>สำหรับบริการอะแดปเตอร์การซิงค์จะชี้ไปยัง ไฟล์ XMLres/xml/syncadapter.xmlในทางกลับกัน ไฟล์นี้จะระบุ URI สำหรับเว็บเซอร์วิสที่จะซิงค์กับ Contacts Provider และประเภทบัญชีสำหรับเว็บเซอร์วิส -
ไม่บังคับ: องค์ประกอบ
<meta-data>สำหรับเครื่องมือตรวจสอบสิทธิ์จะชี้ไปยังไฟล์ XMLres/xml/authenticator.xmlซึ่งไฟล์นี้จะระบุ ประเภทบัญชีที่เครื่องมือตรวจสอบสิทธิ์นี้รองรับ รวมถึงทรัพยากร UI ที่ ปรากฏในระหว่างกระบวนการตรวจสอบสิทธิ์ ประเภทบัญชีที่ระบุในองค์ประกอบนี้ ต้องเหมือนกับประเภทบัญชีที่ระบุสําหรับอะแดปเตอร์การซิงค์
-
องค์ประกอบ
ข้อมูลสตรีมโซเชียล
ตาราง android.provider.ContactsContract.StreamItems และ android.provider.ContactsContract.StreamItemPhotos จัดการข้อมูลขาเข้าจากโซเชียลเน็ตเวิร์ก คุณสามารถเขียนตัวดัดแปลงการซิงค์ที่เพิ่มข้อมูลสตรีม จากเครือข่ายของคุณเองลงในตารางเหล่านี้ หรือจะอ่านข้อมูลสตรีมจากตารางเหล่านี้และ แสดงในแอปพลิเคชันของคุณเอง หรือทั้ง 2 อย่างก็ได้ ฟีเจอร์เหล่านี้ช่วยให้คุณผสานรวมบริการและแอปพลิเคชันเครือข่ายสังคมออนไลน์ เข้ากับประสบการณ์การใช้งานเครือข่ายสังคมออนไลน์ของ Android ได้
ข้อความสตรีมโซเชียล
รายการสตรีมจะเชื่อมโยงกับข้อมูลติดต่อดิบเสมอ android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID ลิงก์ไปยัง
_ID ค่าสำหรับข้อมูลติดต่อดิบ ระบบจะจัดเก็บประเภทบัญชีและชื่อบัญชีของ
รายชื่อติดต่อดิบไว้ในแถวของรายการสตรีมด้วย
จัดเก็บข้อมูลจากสตรีมในคอลัมน์ต่อไปนี้
- android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE
- ต้องระบุ ประเภทบัญชีของผู้ใช้สำหรับข้อมูลติดต่อดิบที่เชื่อมโยงกับรายการสตรีมนี้ อย่าลืมตั้งค่านี้เมื่อแทรกรายการสตรีม
- android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME
- ต้องระบุ ชื่อบัญชีของผู้ใช้สำหรับข้อมูลติดต่อดิบที่เชื่อมโยงกับรายการสตรีมนี้ อย่าลืมตั้งค่านี้เมื่อแทรกรายการสตรีม
- คอลัมน์ตัวระบุ
-
ต้องระบุ คุณต้องแทรกคอลัมน์ตัวระบุต่อไปนี้เมื่อ
แทรกรายการสตรีม
- android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID: ค่า android.provider.BaseColumns#_ID ของรายชื่อติดต่อที่รายการสตรีมนี้ เชื่อมโยงอยู่
- android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY: ค่า android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY ของ รายชื่อติดต่อที่เชื่อมโยงกับรายการสตรีมนี้
- android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID: ค่า android.provider.BaseColumns#_ID ของข้อมูลติดต่อดิบที่รายการสตรีมนี้ เชื่อมโยงอยู่
- android.provider.ContactsContract.StreamItemsColumns#COMMENTS
- ไม่บังคับ จัดเก็บข้อมูลสรุปของร้านค้าที่คุณแสดงได้ที่จุดเริ่มต้นของรายการสตรีม
- android.provider.ContactsContract.StreamItemsColumns#TEXT
-
ข้อความของรายการสตรีม ไม่ว่าจะเป็นเนื้อหาที่แหล่งที่มาของรายการโพสต์
หรือคำอธิบายของการดำเนินการบางอย่างที่สร้างรายการสตรีม คอลัมน์นี้อาจมีการจัดรูปแบบและรูปภาพทรัพยากรที่ฝังอยู่ซึ่ง
fromHtml()แสดงผลได้ ผู้ให้บริการอาจตัดทอนหรือ ละเนื้อหาที่ยาว แต่จะพยายามไม่ให้แท็กขาด - android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP
- สตริงข้อความที่มีเวลาที่แทรกหรืออัปเดตรายการสตรีมในรูปแบบมิลลิวินาทีตั้งแต่ Epoch แอปพลิเคชันที่แทรกหรืออัปเดตรายการสตรีมมี หน้าที่ดูแลคอลัมน์นี้ โดย Contacts Provider จะไม่ดูแลคอลัมน์นี้โดยอัตโนมัติ
หากต้องการแสดงข้อมูลระบุตัวบุคคลสำหรับรายการสตรีม ให้ใช้ android.provider.ContactsContract.StreamItemsColumns#RES_ICON, android.provider.ContactsContract.StreamItemsColumns#RES_LABEL และ android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE เพื่อลิงก์ไปยังทรัพยากร ในแอปพลิเคชัน
ตาราง android.provider.ContactsContract.StreamItems ยังมีคอลัมน์ android.provider.ContactsContract.StreamItemsColumns#SYNC1 ถึง android.provider.ContactsContract.StreamItemsColumns#SYNC4 สำหรับใช้โดย Sync Adapter เท่านั้น
รูปภาพในสตรีมโซเชียล
ตาราง android.provider.ContactsContract.StreamItemPhotos จะจัดเก็บรูปภาพที่เชื่อมโยง
กับรายการสตรีม คอลัมน์ android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID ของตาราง
ลิงก์ไปยังค่าในคอลัมน์ _ID ของ
ตาราง android.provider.ContactsContract.StreamItems ระบบจะจัดเก็บข้อมูลอ้างอิงรูปภาพไว้ในตาราง
ในคอลัมน์ต่อไปนี้
- คอลัมน์ android.provider.ContactsContract.StreamItemPhotos#PHOTO (BLOB)
- การแสดงรูปภาพในรูปแบบไบนารี ซึ่งผู้ให้บริการปรับขนาดเพื่อจัดเก็บและแสดง คอลัมน์นี้มีไว้เพื่อความเข้ากันได้แบบย้อนหลังกับ Contacts Provider เวอร์ชันก่อนหน้าซึ่งใช้คอลัมน์นี้ในการจัดเก็บรูปภาพ อย่างไรก็ตาม ในเวอร์ชันปัจจุบัน คุณไม่ควรใช้คอลัมน์นี้เพื่อจัดเก็บรูปภาพ แต่ให้ใช้ android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID หรือ android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI (ทั้ง 2 รายการ อธิบายไว้ในจุดต่อไปนี้) เพื่อจัดเก็บรูปภาพในไฟล์แทน ตอนนี้คอลัมน์นี้ มีภาพขนาดย่อของรูปภาพซึ่งพร้อมให้อ่านแล้ว
- android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID
-
ตัวระบุตัวเลขของรูปภาพสำหรับข้อมูลติดต่อดิบ ผนวกค่านี้เข้ากับค่าคงที่
DisplayPhoto.CONTENT_URIเพื่อรับ URI เนื้อหาที่ชี้ไปยังไฟล์รูปภาพเดียว แล้วเรียกใช้openAssetFileDescriptor()เพื่อรับแฮนเดิลไปยังไฟล์รูปภาพ - android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI
-
URI เนื้อหาที่ชี้ไปยังไฟล์รูปภาพโดยตรงสำหรับรูปภาพที่แถวนี้แสดง
โทรหา
openAssetFileDescriptor()ด้วย URI นี้เพื่อรับแฮนเดิลไปยังไฟล์รูปภาพ
การใช้ตารางสตรีมโซเชียล
ตารางเหล่านี้ทำงานเหมือนกับตารางหลักอื่นๆ ใน Contacts Provider ยกเว้นในกรณีต่อไปนี้
- ตารางเหล่านี้ต้องมีสิทธิ์เข้าถึงเพิ่มเติม หากต้องการอ่านข้อมูลจากสตรีมเหล่านั้น แอปพลิเคชันของคุณ ต้องมีสิทธิ์ android.Manifest.permission#READ_SOCIAL_STREAM หากต้องการ แก้ไขแอตทริบิวต์เหล่านี้ แอปพลิเคชันของคุณต้องมีสิทธิ์ android.Manifest.permission#WRITE_SOCIAL_STREAM
-
สำหรับตาราง android.provider.ContactsContract.StreamItems ระบบจะจำกัดจำนวนแถว
ที่จัดเก็บสำหรับข้อมูลติดต่อดิบแต่ละรายการ เมื่อถึงขีดจำกัดนี้แล้ว
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 การลงทะเบียนการแจ้งเตือนและ การเชิญผู้ติดต่อจะกล่าวถึงใน 2 ส่วนถัดไป
การลงทะเบียนเพื่อจัดการการดูโซเชียลเน็ตเวิร์ก
หากต้องการลงทะเบียนอะแดปเตอร์การซิงค์เพื่อรับการแจ้งเตือนเมื่อผู้ใช้ดูรายชื่อติดต่อที่ อะแดปเตอร์การซิงค์ของคุณจัดการ ให้ทำดังนี้
-
สร้างไฟล์ชื่อ
contacts.xmlในไดเรกทอรีres/xml/ของโปรเจ็กต์ หากมีไฟล์นี้อยู่แล้ว ให้ข้ามขั้นตอนนี้ -
ในไฟล์นี้ ให้เพิ่มองค์ประกอบ
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">หากมีองค์ประกอบนี้อยู่แล้ว ให้ข้ามขั้นตอนนี้ -
หากต้องการลงทะเบียนบริการที่จะได้รับการแจ้งเตือนเมื่อผู้ใช้เปิดหน้ารายละเอียดของรายชื่อติดต่อในแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ ให้เพิ่มแอตทริบิวต์
viewContactNotifyService="serviceclass"ไปยังองค์ประกอบ โดยที่serviceclassคือชื่อคลาสแบบเต็มของบริการ ที่ควรได้รับ Intent จากแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ สำหรับบริการแจ้งเตือน ให้ใช้คลาสที่ขยายIntentServiceเพื่อให้บริการรับ Intent ได้ ข้อมูลใน Intent ขาเข้ามี URI เนื้อหาของรายชื่อติดต่อดิบที่ผู้ใช้คลิก จากบริการแจ้งเตือน คุณสามารถเชื่อมโยงและเรียกใช้ อะแดปเตอร์การซิงค์ เพื่ออัปเดตข้อมูลสำหรับข้อมูลติดต่อดิบ
หากต้องการลงทะเบียนกิจกรรมที่จะเรียกใช้เมื่อผู้ใช้คลิกรายการในสตรีมหรือรูปภาพ หรือทั้ง 2 อย่าง ให้ทำดังนี้
-
สร้างไฟล์ชื่อ
contacts.xmlในไดเรกทอรีres/xml/ของโปรเจ็กต์ หากมีไฟล์นี้อยู่แล้ว ให้ข้ามขั้นตอนนี้ -
ในไฟล์นี้ ให้เพิ่มองค์ประกอบ
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">หากมีองค์ประกอบนี้อยู่แล้ว ให้ข้ามขั้นตอนนี้ -
หากต้องการลงทะเบียนกิจกรรมอย่างใดอย่างหนึ่งเพื่อจัดการเมื่อผู้ใช้คลิกรายการในสตรีมในแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ ให้เพิ่มแอตทริบิวต์
viewStreamItemActivity="activityclass"ลงในองค์ประกอบ โดยที่activityclassคือชื่อคลาสแบบเต็มของกิจกรรม ที่ควรรับ Intent จากแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ -
หากต้องการลงทะเบียนกิจกรรมอย่างใดอย่างหนึ่งเพื่อจัดการเมื่อผู้ใช้คลิกรูปภาพในสตรีมในแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์ ให้เพิ่มแอตทริบิวต์
viewStreamItemPhotoActivity="activityclass"ลงในองค์ประกอบ โดยที่activityclassคือชื่อคลาสแบบเต็มของกิจกรรม ที่ควรรับ Intent จากแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์
องค์ประกอบ <ContactsAccountType> มีคำอธิบายโดยละเอียดในส่วนองค์ประกอบ<ContactsAccountType>
Intent ขาเข้ามี URI เนื้อหาของรายการหรือรูปภาพที่ผู้ใช้คลิก หากต้องการมีกิจกรรมแยกกันสำหรับรายการข้อความและรูปภาพ ให้ใช้ทั้ง 2 แอตทริบิวต์ในไฟล์เดียวกัน
การโต้ตอบกับบริการโซเชียลเน็ตเวิร์ก
ผู้ใช้ไม่จำเป็นต้องออกจากแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์เพื่อเชิญรายชื่อติดต่อไปยังเว็บไซต์เครือข่ายสังคมของคุณ แต่คุณสามารถให้แอปรายชื่อติดต่อของอุปกรณ์ส่ง Intent สำหรับเชิญ รายชื่อติดต่อเข้าร่วมกิจกรรมอย่างใดอย่างหนึ่งของคุณได้ โดยมีวิธีการตั้งค่าดังนี้
-
สร้างไฟล์ชื่อ
contacts.xmlในไดเรกทอรีres/xml/ของโปรเจ็กต์ หากมีไฟล์นี้อยู่แล้ว ให้ข้ามขั้นตอนนี้ -
ในไฟล์นี้ ให้เพิ่มองค์ประกอบ
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">หากมีองค์ประกอบนี้อยู่แล้ว ให้ข้ามขั้นตอนนี้ -
เพิ่มแอตทริบิวต์ต่อไปนี้
inviteContactActivity="activityclass"-
inviteContactActionLabel="@string/invite_action_label"
activityclassคือชื่อคลาสแบบเต็มของ กิจกรรมที่ควรได้รับ Intentinvite_action_labelค่าคือสตริงข้อความที่แสดงในเมนูเพิ่มการเชื่อมต่อในแอปพลิเคชันรายชื่อผู้ติดต่อของอุปกรณ์
หมายเหตุ: ContactsSource เป็นชื่อแท็กที่เลิกใช้งานแล้วสำหรับ
ContactsAccountType
การอ้างอิง contacts.xml
ไฟล์ contacts.xml มีองค์ประกอบ XML ที่ควบคุมการโต้ตอบของอะแดปเตอร์การซิงค์และแอปพลิเคชันกับแอปพลิเคชันรายชื่อผู้ติดต่อและ 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> 1 รายการสําหรับประเภท MIME ที่กําหนดเองแต่ละประเภทที่คุณใช้ คุณไม่จำเป็นต้องเพิ่มองค์ประกอบนี้หากมีแถวข้อมูลที่กำหนดเองซึ่งคุณไม่ต้องการแสดงข้อมูล
แอตทริบิวต์
android:mimeType-
ประเภท MIME ที่กำหนดเองที่คุณกำหนดไว้สำหรับประเภทแถวข้อมูลที่กำหนดเองประเภทใดประเภทหนึ่งในตาราง
ContactsContract.Dataเช่น ค่าvnd.android.cursor.item/vnd.example.locationstatusอาจเป็นประเภท MIME ที่กำหนดเองสำหรับแถวข้อมูลที่บันทึกตำแหน่งล่าสุดที่ทราบของรายชื่อติดต่อ android:icon- Android ทรัพยากร Drawable ที่แอปพลิเคชันรายชื่อติดต่อแสดงข้างข้อมูลของคุณ ใช้เพื่อระบุให้ผู้ใช้ทราบว่าข้อมูลมาจากบริการของคุณ
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 ซึ่งอธิบายรายละเอียดเพิ่มเติม ในส่วนรูปภาพในสตรีมโซเชียล