ผู้ให้บริการรายชื่อติดต่อคือคอมโพเนนต์ Android ที่มีประสิทธิภาพและยืดหยุ่นซึ่งจัดการที่เก็บข้อมูลกลางของอุปกรณ์เกี่ยวกับบุคคล ผู้ให้บริการรายชื่อติดต่อเป็นแหล่งที่มาของข้อมูลที่คุณเห็นในแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ และคุณยังเข้าถึงข้อมูลดังกล่าวในแอปพลิเคชันของคุณเอง รวมถึงโอนข้อมูลระหว่างอุปกรณ์กับบริการออนไลน์ได้ด้วย ผู้ให้บริการรองรับแหล่งข้อมูลหลากหลายประเภทและพยายามจัดการข้อมูลให้มากที่สุดสำหรับแต่ละบุคคล ส่งผลให้องค์กรมีความซับซ้อน ด้วยเหตุนี้ API ของผู้ให้บริการจึงมีชุดคลาสและอินเทอร์เฟซสัญญาที่ครอบคลุม ซึ่งช่วยให้ทั้งการดึงข้อมูลและการแก้ไขเป็นไปอย่างสะดวก
คู่มือนี้จะอธิบายข้อมูลต่อไปนี้
- โครงสร้างพื้นฐานของผู้ให้บริการ
- วิธีเรียกข้อมูลจากผู้ให้บริการ
- วิธีแก้ไขข้อมูลในผู้ให้บริการ
- วิธีเขียนอะแดปเตอร์การซิงค์สำหรับการซิงค์ข้อมูลจากเซิร์ฟเวอร์กับผู้ให้บริการรายชื่อติดต่อ
คู่มือนี้จะถือว่าคุณทราบข้อมูลเบื้องต้นเกี่ยวกับผู้ให้บริการเนื้อหา Android หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับผู้ให้บริการเนื้อหา Android โปรดอ่านคู่มือ ข้อมูลเบื้องต้นเกี่ยวกับผู้ให้บริการเนื้อหา
องค์กรของ Contacts Provider
Contacts Provider เป็นคอมโพเนนต์ผู้ให้บริการเนื้อหา Android โดยเก็บข้อมูลเกี่ยวกับบุคคล 3 ประเภท ซึ่งแต่ละประเภทจะสอดคล้องกับตารางที่ผู้ให้บริการนำเสนอ ดังที่แสดงในรูปที่ 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 โปรดอ่านหมายเหตุที่แสดงอยู่หลังตาราง
ชื่อคอลัมน์ | ใช้ | หมายเหตุ |
---|---|---|
ACCOUNT_NAME
|
ชื่อบัญชีสําหรับประเภทบัญชีที่เป็นแหล่งที่มาของข้อมูลติดต่อดิบนี้
เช่น ชื่อบัญชีของบัญชี Google คืออีเมล Gmail ของเจ้าของอุปกรณ์ ดูข้อมูลเพิ่มเติมได้ในส่วนถัดไปสำหรับ ACCOUNT_TYPE
|
รูปแบบของชื่อนี้จะเจาะจงสำหรับประเภทบัญชี โดยไม่จำเป็นต้องเป็นอีเมล |
ACCOUNT_TYPE
|
ประเภทบัญชีที่เป็นแหล่งที่มาของข้อมูลติดต่อดิบนี้ เช่น ประเภทบัญชี Google คือ com.google ระบุประเภทบัญชีด้วยตัวระบุโดเมนของโดเมนที่คุณเป็นเจ้าของหรือควบคุมเสมอ วิธีนี้จะช่วยให้ประเภทบัญชีของคุณไม่ซ้ำกัน
|
โดยทั่วไปแล้ว บัญชีประเภทที่ให้บริการข้อมูลรายชื่อติดต่อจะมีอะแดปเตอร์การซิงค์ที่เชื่อมโยงซึ่งจะซิงค์กับผู้ให้บริการรายชื่อติดต่อ |
DELETED
|
ธง "deleted" สำหรับรายชื่อติดต่อแบบไฟล์ดิบ | Flag นี้ช่วยให้ผู้ให้บริการ Contacts ดูแลรักษาแถวดังกล่าวภายในได้จนกว่าอะแดปเตอร์การซิงค์จะลบแถวออกจากเซิร์ฟเวอร์ได้ แล้วจึงลบแถวออกจากที่เก็บข้อมูล |
หมายเหตุ
หมายเหตุสำคัญเกี่ยวกับตาราง 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 บัญชีเหล่านี้ในการตั้งค่าบัญชี
สมมติว่า Emily Dickinson เปิดหน้าต่างเบราว์เซอร์ เข้าสู่ระบบ Gmail โดยใช้อีเมล emily.dickinson@gmail.com
เปิด Contacts แล้วเพิ่ม "Thomas Higginson" ต่อมา เธอเข้าสู่ระบบ Gmail โดยใช้บัญชี emilyd@gmail.com
และส่งอีเมลถึง "Thomas Higginson" ซึ่งจะเพิ่มเขาเป็นรายชื่อติดต่อโดยอัตโนมัติ นอกจากนี้ เธอยังติดตาม "colonel_tom" (รหัส Twitter ของ Thomas Higginson) บน Twitter ด้วย
ผู้ให้บริการ Contacts จะสร้างรายชื่อติดต่อดิบ 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.CommonDataKinds
ประเภท MIME เหล่านี้เป็นแบบโอเพนซอร์ส และสามารถใช้กับแอปพลิเคชันหรืออะแดปเตอร์การซิงค์ใดก็ได้ที่ทำงานร่วมกับผู้ให้บริการ Contacts -
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 แสดงคลาสชื่อคอลัมน์ตามประเภทที่ใช้กันมากที่สุด
การแมปคลาส | ประเภทของข้อมูล | หมายเหตุ |
---|---|---|
ContactsContract.CommonDataKinds.StructuredName |
ข้อมูลชื่อของรายชื่อติดต่อดิบซึ่งเชื่อมโยงกับแถวข้อมูลนี้ | รายชื่อติดต่อดิบจะมีเพียงแถวใดแถวหนึ่งเท่านั้น |
ContactsContract.CommonDataKinds.Photo |
รูปภาพหลักสำหรับรายชื่อติดต่อดิบที่เชื่อมโยงกับแถวข้อมูลนี้ | รายชื่อติดต่อดิบจะมีเพียงแถวใดแถวหนึ่งเท่านั้น |
ContactsContract.CommonDataKinds.Email |
อีเมลสําหรับรายชื่อติดต่อดิบซึ่งเชื่อมโยงกับแถวข้อมูลนี้ | รายชื่อติดต่อแบบไฟล์ดิบอาจมีอีเมลได้หลายรายการ |
ContactsContract.CommonDataKinds.StructuredPostal |
ที่อยู่ไปรษณีย์ของผู้ติดต่อแบบไฟล์ดิบซึ่งเชื่อมโยงกับแถวข้อมูลนี้ | รายชื่อติดต่อแบบไฟล์ดิบอาจมีที่อยู่ไปรษณีย์ได้หลายรายการ |
ContactsContract.CommonDataKinds.GroupMembership |
ตัวระบุที่ลิงก์รายชื่อติดต่อดิบกับกลุ่มใดกลุ่มหนึ่งในผู้ให้บริการ Contacts | กลุ่มเป็นฟีเจอร์ที่ไม่บังคับของประเภทบัญชีและชื่อบัญชี ซึ่งอธิบายไว้อย่างละเอียดในส่วนกลุ่มรายชื่อติดต่อ |
รายชื่อติดต่อ
Contacts Provider จะรวมแถวรายชื่อติดต่อดิบของบัญชีทุกประเภทและชื่อบัญชีเข้าด้วยกันเพื่อสร้างรายชื่อติดต่อ ซึ่งช่วยให้แสดงและแก้ไขข้อมูลทั้งหมดที่ผู้ใช้รวบรวมไว้สำหรับบุคคลหนึ่งๆ ได้ ผู้ให้บริการรายชื่อติดต่อจะจัดการการสร้างแถวรายชื่อติดต่อใหม่ และการรวมรายชื่อติดต่อดิบเข้ากับแถวรายชื่อติดต่อที่มีอยู่ แอปพลิเคชันและอะแดปเตอร์การซิงค์ไม่ได้รับอนุญาตให้เพิ่มรายชื่อติดต่อ และบางคอลัมน์ในแถวรายชื่อติดต่อจะมีสิทธิ์อ่านอย่างเดียว
หมายเหตุ: หากพยายามเพิ่มรายชื่อติดต่อไปยังผู้ให้บริการรายชื่อติดต่อที่มี insert()
คุณจะได้รับข้อยกเว้น UnsupportedOperationException
หากคุณพยายามอัปเดตคอลัมน์ที่ระบุว่า "อ่านอย่างเดียว" ระบบจะไม่สนใจการอัปเดต
ผู้ให้บริการ Contacts จะสร้างรายชื่อติดต่อใหม่เพื่อตอบสนองต่อการเพิ่มรายชื่อติดต่อใหม่ในรูปแบบข้อมูลดิบซึ่งไม่ตรงกับรายชื่อติดต่อที่มีอยู่ ผู้ให้บริการจะดำเนินการนี้ด้วยหากข้อมูลติดต่อดิบที่มีอยู่มีการเปลี่ยนแปลงในลักษณะที่ไม่ตรงกับรายชื่อติดต่อที่แนบไว้ก่อนหน้านี้อีกต่อไป หากแอปพลิเคชันหรืออะแดปเตอร์การซิงค์สร้างข้อมูลติดต่อดิบใหม่ซึ่งตรงกับรายชื่อติดต่อที่มีอยู่ ระบบจะรวมข้อมูลติดต่อดิบใหม่เข้ากับรายชื่อติดต่อที่มีอยู่
ผู้ให้บริการรายชื่อติดต่อจะลิงก์แถวรายชื่อติดต่อกับแถวรายชื่อติดต่อดิบด้วยคอลัมน์ _ID
ของแถวรายชื่อติดต่อในตาราง Contacts
คอลัมน์ CONTACT_ID
ของตารางรายชื่อติดต่อดิบ ContactsContract.RawContacts
มีค่า _ID
สำหรับแถวรายชื่อติดต่อที่เชื่อมโยงกับแถวรายชื่อติดต่อดิบแต่ละแถว
ตาราง ContactsContract.Contacts
ยังมีคอลัมน์ LOOKUP_KEY
ซึ่งเป็นลิงก์ "ถาวร" ไปยังแถวรายชื่อติดต่อด้วย เนื่องจากผู้ให้บริการข้อมูลติดต่อจะดูแลรักษารายชื่อติดต่อโดยอัตโนมัติ จึงอาจเปลี่ยนค่า _ID
ของแถวรายชื่อติดต่อเพื่อตอบสนองต่อการรวบรวมหรือซิงค์ แม้จะเกิดเหตุการณ์นี้ URI ของเนื้อหา
CONTENT_LOOKUP_URI
ที่รวมกับ LOOKUP_KEY
ของรายชื่อติดต่อจะยังคงชี้ไปยังแถวรายชื่อติดต่อ คุณจึงใช้ LOOKUP_KEY
เพื่อเก็บลิงก์ไปยังรายชื่อติดต่อ "รายการโปรด" และอื่นๆ ได้ คอลัมน์นี้มีรูปแบบเป็นของตัวเองซึ่งไม่เกี่ยวข้องกับรูปแบบของคอลัมน์ _ID
รูปที่ 3 แสดงความสัมพันธ์ของตารางหลัก 3 ตาราง
ข้อควรระวัง: หากคุณเผยแพร่แอปใน Google Play Store หรือหากแอปของคุณอยู่ในอุปกรณ์ที่ใช้ Android 10 (API ระดับ 29) ขึ้นไป โปรดทราบว่าช่องและเมธอดข้อมูลรายชื่อติดต่อแบบจํากัดจะใช้งานไม่ได้
ภายใต้เงื่อนไขที่กล่าวถึง ระบบจะล้างค่าที่เขียนลงในช่องข้อมูลต่อไปนี้เป็นระยะ
-
ContactsContract.ContactOptionsColumns.LAST_TIME_CONTACTED
-
ContactsContract.ContactOptionsColumns.TIMES_CONTACTED
-
ContactsContract.DataUsageStatColumns.LAST_TIME_USED
-
ContactsContract.DataUsageStatColumns.TIMES_USED
API ที่ใช้ตั้งค่าช่องข้อมูลข้างต้นก็ล้าสมัยเช่นกัน
นอกจากนี้ ฟิลด์ต่อไปนี้จะไม่แสดงรายชื่อติดต่อที่ติดต่อบ่อยอีกต่อไป โปรดทราบว่าช่องบางช่องเหล่านี้จะส่งผลต่อการจัดอันดับรายชื่อติดต่อก็ต่อเมื่อรายชื่อติดต่อเป็นส่วนหนึ่งของประเภทข้อมูลที่เฉพาะเจาะจงเท่านั้น
-
ContactsContract.Contacts.CONTENT_FREQUENT_URI
-
ContactsContract.Contacts.CONTENT_STREQUENT_URI
-
ContactsContract.Contacts.CONTENT_STREQUENT_FILTER_URI
-
CONTENT_FILTER_URI
(มีผลเฉพาะกับประเภทข้อมูลอีเมล โทรศัพท์ โทรได้ และผู้ติดต่อได้) -
ENTERPRISE_CONTENT_FILTER_URI
(มีผลเฉพาะกับประเภทข้อมูลอีเมล โทรศัพท์ และเรียกได้)
หากแอปของคุณเข้าถึงหรืออัปเดตช่องหรือ API เหล่านี้ ให้ใช้วิธีอื่น ตัวอย่างเช่น คุณสามารถตอบสนอง Use Case บางรายการได้โดยใช้ผู้ให้บริการเนื้อหาส่วนตัวหรือข้อมูลอื่นๆ ที่เก็บไว้ในแอปหรือระบบแบ็กเอนด์
หากต้องการยืนยันว่าฟังก์ชันการทำงานของแอปไม่ได้รับผลกระทบจากการเปลี่ยนแปลงนี้ คุณสามารถล้างช่องข้อมูลเหล่านี้ด้วยตนเองได้ โดยให้เรียกใช้คําสั่ง ADB ต่อไปนี้ในอุปกรณ์ที่ใช้ Android 4.1 (API ระดับ 16) ขึ้นไป
adb shell content delete \ --uri content://com.android.contacts/contacts/delete_usage
ข้อมูลจากอะแดปเตอร์การซิงค์
ผู้ใช้ป้อนข้อมูลรายชื่อติดต่อลงในอุปกรณ์โดยตรง แต่ข้อมูลจะส่งไปยังผู้ให้บริการรายชื่อติดต่อจากบริการเว็บผ่านอะแดปเตอร์การซิงค์ด้วย ซึ่งจะโอนข้อมูลระหว่างอุปกรณ์กับบริการโดยอัตโนมัติ อะแดปเตอร์การซิงค์จะทำงานอยู่เบื้องหลังภายใต้การควบคุมของระบบ และจะเรียกใช้เมธอด ContentResolver
เพื่อจัดการข้อมูล
ใน Android เว็บเซอร์วิสที่อะแดปเตอร์การซิงค์ทำงานด้วยจะระบุตามประเภทบัญชี ตัวเชื่อมข้อมูลแต่ละรายการจะใช้งานได้กับบัญชี 1 ประเภท แต่รองรับชื่อบัญชีหลายรายการสำหรับประเภทนั้น ประเภทบัญชีและชื่อบัญชีจะอธิบายไว้อย่างคร่าวๆ ในส่วนแหล่งที่มาของข้อมูลติดต่อดิบ คําจํากัดความต่อไปนี้ให้รายละเอียดเพิ่มเติมและอธิบายความสัมพันธ์ระหว่างประเภทและชื่อบัญชีกับอะแดปเตอร์และบริการการซิงค์
- ประเภทบัญชี
-
ระบุบริการที่ผู้ใช้จัดเก็บข้อมูลไว้ ส่วนใหญ่แล้ว ผู้ใช้จะต้องตรวจสอบสิทธิ์กับบริการ เช่น Google Contacts เป็นประเภทบัญชีที่ระบุด้วยรหัส
google.com
ค่านี้สอดคล้องกับประเภทบัญชีที่ใช้โดยAccountManager
- ชื่อบัญชี
- ระบุบัญชีหรือการเข้าสู่ระบบที่เฉพาะเจาะจงสําหรับประเภทบัญชี บัญชี Google Contacts เหมือนกับบัญชี Google ซึ่งมีอีเมลเป็นชื่อบัญชี บริการอื่นๆ อาจใช้ชื่อผู้ใช้แบบคำเดียวหรือรหัสตัวเลข
ประเภทบัญชีไม่จำเป็นต้องไม่ซ้ำกัน ผู้ใช้สามารถกำหนดค่าบัญชี Google Contacts หลายบัญชีและดาวน์โหลดข้อมูลไปยังผู้ให้บริการ Contacts ได้ ซึ่งอาจเกิดขึ้นหากผู้ใช้มีรายชื่อติดต่อส่วนตัวชุดหนึ่งสำหรับชื่อบัญชีส่วนตัว และอีกชุดสำหรับงาน โดยปกติแล้วชื่อบัญชีจะซ้ำกันไม่ได้ ข้อมูลเหล่านี้จะระบุการไหลของข้อมูลระหว่างผู้ให้บริการรายชื่อติดต่อกับบริการภายนอก
หากต้องการโอนข้อมูลบริการไปยังผู้ให้บริการรายชื่อติดต่อ คุณต้องเขียนอะแดปเตอร์การซิงค์ของคุณเอง ซึ่งอธิบายไว้อย่างละเอียดในส่วนอะแดปเตอร์การซิงค์ของผู้ให้บริการรายชื่อติดต่อ
รูปที่ 4 แสดงวิธีที่ผู้ให้บริการรายชื่อติดต่อทำงานร่วมกับการไหลของข้อมูลเกี่ยวกับบุคคล ในช่อง "อะแดปเตอร์การซิงค์" อะแดปเตอร์แต่ละตัวจะมีป้ายกำกับตามประเภทบัญชี
สิทธิ์ที่จำเป็น
แอปพลิเคชันที่ต้องการเข้าถึงผู้ให้บริการรายชื่อติดต่อต้องขอสิทธิ์ต่อไปนี้
- สิทธิ์การอ่านตารางอย่างน้อย 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 จะจัดการข้อมูลที่ติดตามสถานะข้อมูลรายชื่อติดต่อในที่เก็บข้อมูล ข้อมูลเมตาเกี่ยวกับที่เก็บข้อมูลนี้จัดเก็บไว้ในที่ต่างๆ ซึ่งรวมถึงแถวตารางรายชื่อติดต่อดิบ ข้อมูล และรายชื่อติดต่อ ตาราง ContactsContract.Settings
และตาราง ContactsContract.SyncState
ตารางต่อไปนี้แสดงผลของข้อมูลเมตาแต่ละรายการ
ตาราง | คอลัมน์ | ค่า | ความหมาย |
---|---|---|---|
ContactsContract.RawContacts |
DIRTY |
"0" - ไม่มีการเปลี่ยนแปลงนับตั้งแต่ซิงค์ครั้งล่าสุด |
ทำเครื่องหมายรายชื่อติดต่อดิบที่มีการเปลี่ยนแปลงในอุปกรณ์และต้องซิงค์กลับไปกับเซิร์ฟเวอร์ ผู้ให้บริการ Contacts จะตั้งค่าโดยอัตโนมัติเมื่อแอปพลิเคชัน Android อัปเดตแถว
อะแดปเตอร์การซิงค์ที่แก้ไขตารางข้อมูลหรือรายชื่อติดต่อดิบควรเพิ่มสตริง |
"1" - มีการเปลี่ยนแปลงนับตั้งแต่การซิงค์ครั้งล่าสุด ต้องซิงค์กลับไปกับเซิร์ฟเวอร์ | |||
ContactsContract.RawContacts |
VERSION |
หมายเลขเวอร์ชันของแถวนี้ | ผู้ให้บริการรายชื่อติดต่อจะเพิ่มค่านี้โดยอัตโนมัติทุกครั้งที่มีการเปลี่ยนแปลงแถวหรือข้อมูลที่เกี่ยวข้อง |
ContactsContract.Data |
DATA_VERSION |
หมายเลขเวอร์ชันของแถวนี้ | ผู้ให้บริการ Contacts จะเพิ่มค่านี้โดยอัตโนมัติทุกครั้งที่มีการเปลี่ยนแปลงแถวข้อมูล |
ContactsContract.RawContacts |
SOURCE_ID |
ค่าสตริงที่ระบุรายชื่อติดต่อดิบนี้ในบัญชีที่สร้างโดยไม่ซ้ำกัน |
เมื่ออะแดปเตอร์การซิงค์สร้างรายชื่อติดต่อดิบใหม่ คุณควรตั้งค่าคอลัมน์นี้เป็นรหัสที่ไม่ซ้ำกันของเซิร์ฟเวอร์สําหรับรายชื่อติดต่อดิบ เมื่อแอปพลิเคชัน Android สร้างรายชื่อติดต่อใหม่แบบไฟล์ดิบ แอปพลิเคชันควรปล่อยคอลัมน์นี้ว่างไว้ ซึ่งจะเป็นสัญญาณให้อะแดปเตอร์การซิงค์ทราบว่าควรสร้างรายชื่อติดต่อใหม่ในเซิร์ฟเวอร์ และรับค่าสำหรับ SOURCE_ID
โดยเฉพาะอย่างยิ่ง รหัสแหล่งที่มาต้องไม่ซ้ำกันสำหรับบัญชีแต่ละประเภทและควรมีความเสถียรในการซิงค์
|
ContactsContract.Groups |
GROUP_VISIBLE |
"0" - รายชื่อติดต่อในกลุ่มนี้ไม่ควรปรากฏใน UI ของแอปพลิเคชัน Android | คอลัมน์นี้มีไว้เพื่อใช้งานร่วมกับเซิร์ฟเวอร์ที่อนุญาตให้ผู้ใช้ซ่อนรายชื่อติดต่อในกลุ่มที่เฉพาะเจาะจง |
"1" - อนุญาตให้รายชื่อติดต่อในกลุ่มนี้ปรากฏใน UI ของแอปพลิเคชัน | |||
ContactsContract.Settings |
UNGROUPED_VISIBLE |
"0" - สำหรับบัญชีและประเภทบัญชีนี้ รายชื่อติดต่อที่ไม่ได้อยู่ในกลุ่มจะมองไม่เห็นใน UI ของแอปพลิเคชัน Android |
โดยค่าเริ่มต้น รายชื่อติดต่อจะมองไม่เห็นหากรายชื่อติดต่อดิบไม่มีรายชื่อติดต่อใดอยู่ในกลุ่ม (การเป็นสมาชิกกลุ่มของรายชื่อติดต่อดิบจะระบุด้วยContactsContract.CommonDataKinds.GroupMembership แถวหรือมากกว่านั้นในตาราง ContactsContract.Data )
การตั้งค่า Flag นี้ในContactsContract.Settings แถวตารางสำหรับประเภทบัญชีและบัญชีจะบังคับให้รายชื่อติดต่อที่ไม่มีกลุ่มแสดง
การใช้ธงนี้อย่างหนึ่งคือการแสดงรายชื่อติดต่อจากเซิร์ฟเวอร์ที่ไม่ได้ใช้กลุ่ม
|
"1" - สำหรับบัญชีและประเภทบัญชีนี้ รายชื่อติดต่อที่ไม่ได้อยู่ในกลุ่มจะแสดงใน UI ของแอปพลิเคชัน | |||
ContactsContract.SyncState |
(ทั้งหมด) | ใช้ตารางนี้เพื่อจัดเก็บข้อมูลเมตาสำหรับอะแดปเตอร์การซิงค์ | ตารางนี้ช่วยให้คุณจัดเก็บสถานะการซิงค์และข้อมูลอื่นๆ ที่เกี่ยวข้องกับการซิงค์ไว้ในอุปกรณ์ได้อย่างต่อเนื่อง |
การเข้าถึง Contacts Provider
ส่วนนี้จะอธิบายหลักเกณฑ์ในการเข้าถึงข้อมูลจากผู้ให้บริการรายชื่อติดต่อ โดยมุ่งเน้นที่สิ่งต่อไปนี้
- การค้นหาเอนทิตี
- การแก้ไขแบบเป็นกลุ่ม
- การดึงข้อมูลและการแก้ไขด้วย Intent
- ความสมบูรณ์ของข้อมูล
การแก้ไขจากอะแดปเตอร์การซิงค์ยังมีรายละเอียดเพิ่มเติมในส่วนอะแดปเตอร์การซิงค์ของ Contacts Provider ด้วย
การค้นหาเอนทิตี
เนื่องจากตารางผู้ให้บริการรายชื่อติดต่อมีการจัดระเบียบเป็นลําดับชั้น จึงมักมีประโยชน์ในการดึงข้อมูลแถวและแถว "ย่อย" ทั้งหมดที่ลิงก์กับแถวนั้น เช่น หากต้องการแสดงข้อมูลทั้งหมดของบุคคลหนึ่ง คุณอาจต้องการดึงข้อมูลแถว ContactsContract.RawContacts
ทั้งหมดสําหรับแถว ContactsContract.Contacts
แถวเดียว หรือแถว ContactsContract.CommonDataKinds.Email
ทั้งหมดสําหรับแถว ContactsContract.RawContacts
แถวเดียว ผู้ให้บริการรายชื่อติดต่อจึงให้บริการคอนสตรัคต์เอนทิตี ซึ่งทํางานเหมือนการรวมฐานข้อมูลระหว่างตารางต่างๆ เพื่ออำนวยความสะดวกในเรื่องนี้
เอนทิตีจะเหมือนกับตารางที่ประกอบด้วยคอลัมน์ที่เลือกจากตารางหลักและตารางย่อย
เมื่อค้นหาเอนทิตี คุณต้องระบุการฉายภาพและเกณฑ์การค้นหาตามคอลัมน์ที่ใช้ได้จากเอนทิตี ผลลัพธ์ที่ได้คือ Cursor
ที่มีแถวละ 1 แถวสําหรับแถวตารางย่อยแต่ละแถวที่ดึงข้อมูล ตัวอย่างเช่น หากคุณค้นหา ContactsContract.Contacts.Entity
สำหรับชื่อรายชื่อติดต่อ และแถว ContactsContract.CommonDataKinds.Email
ทั้งหมดสำหรับรายชื่อติดต่อดิบทั้งหมดของชื่อนั้น คุณจะได้รับ Cursor
ที่มี 1 แถวสำหรับแต่ละแถว ContactsContract.CommonDataKinds.Email
เอนทิตีช่วยให้การค้นหาง่ายขึ้น เมื่อใช้เอนทิตี คุณจะดึงข้อมูลรายชื่อติดต่อทั้งหมดของรายชื่อติดต่อหรือข้อมูลติดต่อดิบได้พร้อมกัน แทนที่จะต้องค้นหาตารางหลักก่อนเพื่อรับรหัส จากนั้นจึงต้องค้นหาตารางย่อยด้วยรหัสนั้น นอกจากนี้ ผู้ให้บริการรายชื่อติดต่อจะประมวลผลการค้นหาเอนทิตีในธุรกรรมเดียว ซึ่งช่วยให้มั่นใจได้ว่าข้อมูลที่ดึงมาจะสอดคล้องกันภายใน
หมายเหตุ: โดยปกติแล้วเอนทิตีจะไม่มีคอลัมน์ทั้งหมดของตารางหลักและตารางย่อย หากคุณพยายามใช้ชื่อคอลัมน์ที่ไม่ได้อยู่ในรายการค่าคงที่ชื่อคอลัมน์สำหรับเอนทิตี คุณจะได้รับ Exception
ข้อมูลโค้ดต่อไปนี้แสดงวิธีดึงข้อมูลแถวรายชื่อติดต่อดิบทั้งหมดสำหรับรายชื่อติดต่อ ข้อมูลโค้ดเป็นส่วนหนึ่งของแอปพลิเคชันขนาดใหญ่ที่มีกิจกรรม 2 รายการ ได้แก่ "main" และ "detail" กิจกรรมหลักจะแสดงรายการแถวรายชื่อติดต่อ เมื่อผู้ใช้เลือกรายการใดรายการหนึ่ง กิจกรรมจะส่งรหัสของรายการนั้นไปยังกิจกรรมแบบละเอียด กิจกรรมแบบละเอียดใช้ ContactsContract.Contacts.Entity
เพื่อแสดงแถวข้อมูลทั้งหมดจากรายชื่อติดต่อดิบทั้งหมดที่เชื่อมโยงกับผู้ติดต่อที่เลือก
ข้อมูลโค้ดนี้นำมาจากกิจกรรม "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
นี้เพื่อแสดงหรือดำเนินการกับข้อมูลต่อได้
การแก้ไขแบบเป็นกลุ่ม
คุณควรแทรก อัปเดต และลบข้อมูลในผู้ให้บริการรายชื่อติดต่อใน "โหมดกลุ่ม" ทุกครั้งที่เป็นไปได้ โดยสร้าง ArrayList
ของออบเจ็กต์ ContentProviderOperation
และเรียกใช้ applyBatch()
เนื่องจากผู้ให้บริการรายชื่อติดต่อจะดําเนินการทั้งหมดใน applyBatch()
ในธุรกรรมเดียว การแก้ไขของคุณจะไม่ทําให้ที่เก็บข้อมูลรายชื่อติดต่ออยู่ในสถานะที่ไม่สอดคล้องกัน การแก้ไขแบบเป็นกลุ่มยังช่วยให้แทรกรายชื่อติดต่อดิบและข้อมูลรายละเอียดของรายชื่อติดต่อได้พร้อมกันด้วย
หมายเหตุ: หากต้องการแก้ไขข้อมูลติดต่อแบบไฟล์ดิบรายการเดียว ให้พิจารณาส่ง Intent ไปยังแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์แทนการจัดการการแก้ไขในแอปของคุณ วิธีการนี้อธิบายไว้อย่างละเอียดในส่วนการเรียกข้อมูลและการแก้ไขด้วย Intent
จุดหยุดชั่วคราว
การแก้ไขแบบเป็นกลุ่มที่มีการดำเนินการจำนวนมากอาจบล็อกกระบวนการอื่นๆ ซึ่งส่งผลให้ผู้ใช้ได้รับประสบการณ์การใช้งานโดยรวมที่ไม่ดี หากต้องการจัดระเบียบการแก้ไขทั้งหมดที่ต้องการดำเนินการในรายการแยกต่างหากให้น้อยที่สุด และขณะเดียวกันก็ป้องกันไม่ให้การแก้ไขบล็อกระบบ คุณควรตั้งค่าจุดผลิตสำหรับการดำเนินการอย่างน้อย 1 รายการ
จุดให้ผลผลิตคือออบเจ็กต์ ContentProviderOperation
ที่ตั้งค่า isYieldAllowed()
เป็น true
เมื่อผู้ให้บริการรายชื่อติดต่อพบจุดที่มีผลตอบแทน ผู้ให้บริการจะหยุดทํางานชั่วคราวเพื่อให้กระบวนการอื่นๆ ทํางานและปิดธุรกรรมปัจจุบัน เมื่อผู้ให้บริการเริ่มทำงานอีกครั้ง ก็จะดำเนินการถัดไปใน ArrayList
และเริ่มธุรกรรมใหม่
คะแนนจากผลตอบแทนจะส่งผลให้มีธุรกรรมมากกว่า 1 รายการต่อการเรียกใช้ applyBatch()
คุณจึงควรตั้งจุดที่มีผลผลิตสําหรับการดำเนินการครั้งล่าสุดสําหรับชุดแถวที่เกี่ยวข้อง
เช่น คุณควรตั้งค่าจุดที่มีอัตราผลตอบแทนสําหรับการดำเนินการสุดท้ายในชุดที่เพิ่มแถวข้อมูลติดต่อดิบและแถวข้อมูลที่เกี่ยวข้อง หรือการดำเนินการสุดท้ายสําหรับชุดแถวที่เกี่ยวข้องกับรายชื่อติดต่อรายการเดียว
จุดที่มีรายได้ยังเป็นหน่วยของการดำเนินการแบบอะตอมมิกด้วย การเข้าถึงทั้งหมดระหว่างจุดที่มีอัตราผลตอบแทน 2 จุดจะสำเร็จหรือล้มเหลวเป็นหน่วยเดียว หากคุณไม่ได้ตั้งค่าจุดให้ผลผลิตใดๆ การดำเนินการแบบอะตอมขนาดเล็กที่สุดคือการดำเนินการทั้งชุด หากใช้จุดที่มีอัตราผลตอบแทน คุณจะป้องกันไม่ให้การดำเนินการทำให้ประสิทธิภาพของระบบลดลง ในขณะเดียวกันก็ตรวจสอบว่าการดำเนินการชุดย่อยเป็นแบบอะตอม
การอ้างอิงย้อนหลังการแก้ไข
เมื่อแทรกแถวข้อมูลติดต่อดิบใหม่และแถวข้อมูลที่เกี่ยวข้องเป็นชุดออบเจ็กต์ ContentProviderOperation
คุณต้องลิงก์แถวข้อมูลกับแถวข้อมูลติดต่อดิบโดยแทรกค่า _ID
ของข้อมูลติดต่อดิบเป็นค่า RAW_CONTACT_ID
อย่างไรก็ตาม ค่านี้จะไม่พร้อมใช้งานเมื่อคุณสร้าง ContentProviderOperation
สำหรับแถวข้อมูล เนื่องจากคุณยังไม่ได้ใช้ ContentProviderOperation
สำหรับแถวข้อมูลติดต่อดิบ วิธีแก้ปัญหานี้คือคลาส ContentProviderOperation.Builder
มีเมธอด withValueBackReference()
วิธีนี้ช่วยให้คุณแทรกหรือแก้ไขคอลัมน์ที่มีผลลัพธ์ของการดำเนินการก่อนหน้าได้
withValueBackReference()
เมธอดนี้มีอาร์กิวเมนต์ 2 รายการ ได้แก่
-
key
- คีย์ของคู่คีย์-ค่า ค่าของอาร์กิวเมนต์นี้ควรเป็นชื่อคอลัมน์ในตารางที่คุณกําลังแก้ไข
-
previousResult
-
ดัชนีฐาน 0 ของค่าในอาร์เรย์ออบเจ็กต์
ContentProviderResult
จากapplyBatch()
เมื่อใช้การดำเนินการแบบเป็นกลุ่ม ระบบจะจัดเก็บผลลัพธ์ของแต่ละการดำเนินการไว้ในอาร์เรย์ผลลัพธ์ระดับกลาง ค่าpreviousResult
คือดัชนีของผลลัพธ์รายการใดรายการหนึ่งเหล่านี้ ซึ่งจะดึงข้อมูลและจัดเก็บไว้กับค่าkey
ซึ่งจะช่วยให้คุณแทรกระเบียนข้อมูลติดต่อดิบใหม่และรับค่า_ID
กลับ จากนั้นทํา "การอ้างอิงกลับ" ไปยังค่าดังกล่าวเมื่อคุณเพิ่มแถวContactsContract.Data
ระบบจะสร้างอาร์เรย์ผลลัพธ์ทั้งหมดเมื่อคุณเรียกใช้
applyBatch()
เป็นครั้งแรก โดยมีขนาดเท่ากับขนาดของArrayList
ของออบเจ็กต์ContentProviderOperation
ที่คุณระบุ อย่างไรก็ตาม ระบบจะตั้งค่าองค์ประกอบทั้งหมดในอาร์เรย์ผลลัพธ์เป็นnull
และหากคุณพยายามอ้างอิงกลับไปยังผลลัพธ์ของการดำเนินการที่ยังไม่ได้ใช้withValueBackReference()
จะแสดงข้อผิดพลาดException
ข้อมูลโค้ดต่อไปนี้แสดงวิธีแทรกรายชื่อติดต่อและข้อมูลใหม่แบบไฟล์ดิบทีละหลายรายการ โดยจะมีโค้ดที่สร้างจุดสิ้นสุดและการใช้การอ้างอิงย้อนกลับ
ข้อมูลโค้ดแรกจะดึงข้อมูลติดต่อจาก UI ณ จุดนี้ ผู้ใช้ได้เลือกบัญชีที่จะเพิ่มรายชื่อติดต่อใหม่แบบไฟล์ดิบแล้ว
Kotlin
// Creates a contact entry from the current UI values, using the currently-selected account. private fun createContactEntry() { /* * Gets values from the UI */ val name = contactNameEditText.text.toString() val phone = contactPhoneEditText.text.toString() val email = contactEmailEditText.text.toString() val phoneType: String = contactPhoneTypes[mContactPhoneTypeSpinner.selectedItemPosition] val emailType: String = contactEmailTypes[mContactEmailTypeSpinner.selectedItemPosition]
Java
// Creates a contact entry from the current UI values, using the currently-selected account. protected void createContactEntry() { /* * Gets values from the UI */ String name = contactNameEditText.getText().toString(); String phone = contactPhoneEditText.getText().toString(); String email = contactEmailEditText.getText().toString(); int phoneType = contactPhoneTypes.get( contactPhoneTypeSpinner.getSelectedItemPosition()); int emailType = contactEmailTypes.get( contactEmailTypeSpinner.getSelectedItemPosition());
ข้อมูลโค้ดถัดไปจะสร้างการดำเนินการเพื่อแทรกแถวรายชื่อติดต่อดิบลงในตาราง ContactsContract.RawContacts
Kotlin
/* * Prepares the batch operation for inserting a new raw contact and its data. Even if * the Contacts Provider does not have any data for this person, you can't add a Contact, * only a raw contact. The Contacts Provider will then add a Contact automatically. */ // Creates a new array of ContentProviderOperation objects. val ops = arrayListOf<ContentProviderOperation>() /* * Creates a new raw contact with its account type (server type) and account name * (user's account). Remember that the display name is not stored in this row, but in a * StructuredName data row. No other data is required. */ var op: ContentProviderOperation.Builder = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.name) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.type) // Builds the operation and adds it to the array of operations ops.add(op.build())
Java
/* * Prepares the batch operation for inserting a new raw contact and its data. Even if * the Contacts Provider does not have any data for this person, you can't add a Contact, * only a raw contact. The Contacts Provider will then add a Contact automatically. */ // Creates a new array of ContentProviderOperation objects. ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); /* * Creates a new raw contact with its account type (server type) and account name * (user's account). Remember that the display name is not stored in this row, but in a * StructuredName data row. No other data is required. */ ContentProviderOperation.Builder op = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.getType()) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.getName()); // Builds the operation and adds it to the array of operations ops.add(op.build());
ถัดไป โค้ดจะสร้างแถวข้อมูลสำหรับแถวชื่อที่แสดง โทรศัพท์ และอีเมล
ออบเจ็กต์ตัวสร้างการดำเนินการแต่ละรายการใช้ withValueBackReference()
เพื่อรับ RAW_CONTACT_ID
รายการอ้างอิงจะกลับไปที่ออบเจ็กต์ ContentProviderResult
จากการดำเนินการแรก ซึ่งจะเพิ่มแถวข้อมูลติดต่อดิบและแสดงค่า _ID
ใหม่ ด้วยเหตุนี้ RAW_CONTACT_ID
แต่ละแถวจึงจะเชื่อมโยงกับContactsContract.RawContacts
แถวใหม่โดยอัตโนมัติ
ออบเจ็กต์ ContentProviderOperation.Builder
ที่เพิ่มแถวอีเมลมีสถานะเป็น withYieldAllowed()
ซึ่งกำหนดจุดที่มีผลผลิต ดังนี้
Kotlin
// Creates the display name for the new raw contact, as a StructuredName data row. op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * withValueBackReference sets the value of the first argument to the value of * the ContentProviderResult indexed by the second argument. In this particular * call, the raw contact ID column of the StructuredName data row is set to the * value of the result returned by the first operation, which is the one that * actually adds the raw contact row. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to StructuredName .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) // Sets the data row's display name to the name in the UI. .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name) // Builds the operation and adds it to the array of operations ops.add(op.build()) // Inserts the specified phone number and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Phone .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Sets the phone number and type .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType) // Builds the operation and adds it to the array of operations ops.add(op.build()) // Inserts the specified email and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Email .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Sets the email address and type .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType) /* * Demonstrates a yield point. At the end of this insert, the batch operation's thread * will yield priority to other threads. Use after every set of operations that affect a * single contact, to avoid degrading performance. */ op.withYieldAllowed(true) // Builds the operation and adds it to the array of operations ops.add(op.build())
Java
// Creates the display name for the new raw contact, as a StructuredName data row. op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * withValueBackReference sets the value of the first argument to the value of * the ContentProviderResult indexed by the second argument. In this particular * call, the raw contact ID column of the StructuredName data row is set to the * value of the result returned by the first operation, which is the one that * actually adds the raw contact row. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to StructuredName .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) // Sets the data row's display name to the name in the UI. .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name); // Builds the operation and adds it to the array of operations ops.add(op.build()); // Inserts the specified phone number and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Phone .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Sets the phone number and type .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType); // Builds the operation and adds it to the array of operations ops.add(op.build()); // Inserts the specified email and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Email .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Sets the email address and type .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType); /* * Demonstrates a yield point. At the end of this insert, the batch operation's thread * will yield priority to other threads. Use after every set of operations that affect a * single contact, to avoid degrading performance. */ op.withYieldAllowed(true); // Builds the operation and adds it to the array of operations ops.add(op.build());
ข้อมูลโค้ดสุดท้ายแสดงการเรียกใช้ applyBatch()
ซึ่งแทรกข้อมูลติดต่อดิบและแถวข้อมูลใหม่
Kotlin
// Ask the Contacts Provider to create a new contact Log.d(TAG, "Selected account: ${mSelectedAccount.name} (${mSelectedAccount.type})") Log.d(TAG, "Creating contact: $name") /* * Applies the array of ContentProviderOperation objects in batch. The results are * discarded. */ try { contentResolver.applyBatch(ContactsContract.AUTHORITY, ops) } catch (e: Exception) { // Display a warning val txt: String = getString(R.string.contactCreationFailure) Toast.makeText(applicationContext, txt, Toast.LENGTH_SHORT).show() // Log exception Log.e(TAG, "Exception encountered while inserting contact: $e") } }
Java
// Ask the Contacts Provider to create a new contact Log.d(TAG,"Selected account: " + selectedAccount.getName() + " (" + selectedAccount.getType() + ")"); Log.d(TAG,"Creating contact: " + name); /* * Applies the array of ContentProviderOperation objects in batch. The results are * discarded. */ try { getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); } catch (Exception e) { // Display a warning Context ctx = getApplicationContext(); CharSequence txt = getString(R.string.contactCreationFailure); int duration = Toast.LENGTH_SHORT; Toast toast = Toast.makeText(ctx, txt, duration); toast.show(); // Log exception Log.e(TAG, "Exception encountered while inserting contact: " + e); } }
นอกจากนี้ การดำเนินการแบบเป็นกลุ่มยังช่วยให้คุณใช้การควบคุมการทํางานพร้อมกันแบบมองโลกในแง่ดี ซึ่งเป็นวิธีการใช้ธุรกรรมการแก้ไขโดยไม่ต้องล็อกที่เก็บข้อมูลพื้นฐาน หากต้องการใช้วิธีนี้ ให้ใช้ธุรกรรมแล้วตรวจสอบการแก้ไขอื่นๆ ที่อาจเกิดขึ้นพร้อมกัน หากพบว่ามีการแก้ไขที่ไม่สอดคล้องกัน คุณสามารถย้อนกลับธุรกรรมและลองอีกครั้ง
การควบคุมการทํางานพร้อมกันแบบมองโลกในแง่ดีมีประโยชน์สําหรับอุปกรณ์เคลื่อนที่ซึ่งมีผู้ใช้เพียงคนเดียวในแต่ละครั้ง และการเข้าถึงที่เก็บข้อมูลพร้อมกันนั้นเกิดขึ้นไม่บ่อย เนื่องจากไม่มีการล็อก คุณจึงไม่ต้องเสียเวลาในการตั้งค่าการล็อกหรือรอให้ธุรกรรมอื่นๆ ยกเลิกการล็อก
หากต้องการใช้การควบคุมการทํางานพร้อมกันแบบมองโลกในแง่ดีขณะอัปเดตContactsContract.RawContacts
แถวเดียว ให้ทําตามขั้นตอนต่อไปนี้
-
ดึงข้อมูลคอลัมน์
VERSION
ของรายชื่อติดต่อดิบพร้อมกับข้อมูลอื่นๆ ที่คุณดึงมา -
สร้างออบเจ็กต์
ContentProviderOperation.Builder
ที่เหมาะสมสําหรับการบังคับใช้ข้อจํากัดโดยใช้เมธอดnewAssertQuery(Uri)
สำหรับ URI ของเนื้อหา ให้ใช้RawContacts.CONTENT_URI
โดยต่อท้ายด้วย_ID
ของข้อมูลติดต่อดิบ -
สําหรับออบเจ็กต์
ContentProviderOperation.Builder
ให้เรียกใช้withValue()
เพื่อเปรียบเทียบคอลัมน์VERSION
กับหมายเลขเวอร์ชันที่คุณเพิ่งดึงข้อมูล -
สําหรับ
ContentProviderOperation.Builder
เดียวกัน ให้เรียกใช้withExpectedCount()
เพื่อให้แน่ใจว่าการยืนยันนี้ทดสอบเพียงแถวเดียว -
เรียกใช้
build()
เพื่อสร้างออบเจ็กต์ContentProviderOperation
จากนั้นเพิ่มออบเจ็กต์นี้เป็นออบเจ็กต์แรกในArrayList
ที่ส่งไปยังapplyBatch()
- ใช้ธุรกรรมกลุ่ม
หากมีการดำเนินการอื่นอัปเดตแถวรายชื่อติดต่อดิบระหว่างที่คุณอ่านแถวนั้นและเวลาที่พยายามแก้ไข การดำเนินการ "ยืนยัน" ContentProviderOperation
จะดำเนินการไม่สำเร็จ และระบบจะยกเลิกการดำเนินการทั้งชุด จากนั้นคุณเลือกที่จะลองส่งอีกครั้งเป็นกลุ่มหรือดำเนินการอื่นๆ ได้
ข้อมูลโค้ดต่อไปนี้แสดงวิธีสร้าง "การยืนยัน"
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 ไปยังแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์จะช่วยให้คุณเข้าถึงผู้ให้บริการรายชื่อติดต่อได้แบบอ้อม Intent จะเริ่มต้น UI ของแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ ซึ่งผู้ใช้สามารถทํางานที่เกี่ยวข้องกับรายชื่อติดต่อได้ ผู้ใช้ที่มีสิทธิ์เข้าถึงประเภทนี้จะทําสิ่งต่อไปนี้ได้
- เลือกรายชื่อติดต่อจากรายการและส่งกลับไปยังแอปเพื่อดำเนินการต่อ
- แก้ไขข้อมูลของรายชื่อติดต่อที่มีอยู่
- แทรกรายชื่อติดต่อใหม่แบบไฟล์ดิบสำหรับบัญชีใดก็ได้
- ลบรายชื่อติดต่อหรือข้อมูลรายชื่อติดต่อ
หากผู้ใช้แทรกหรืออัปเดตข้อมูล คุณสามารถรวบรวมข้อมูลก่อนแล้วส่งข้อมูลดังกล่าวเป็นส่วนหนึ่งของ Intent
เมื่อใช้ Intent เพื่อเข้าถึงผู้ให้บริการรายชื่อติดต่อผ่านแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ คุณไม่จำเป็นต้องเขียน UI หรือโค้ดของคุณเองเพื่อเข้าถึงผู้ให้บริการ นอกจากนี้ คุณยังไม่ต้องขอสิทธิ์ในการอ่านหรือเขียนไปยังผู้ให้บริการด้วย แอปพลิเคชันรายชื่อติดต่อของอุปกรณ์สามารถมอบสิทธิ์การอ่านรายชื่อติดต่อให้คุณได้ และเนื่องจากคุณทำการแก้ไขผู้ให้บริการผ่านแอปพลิเคชันอื่น คุณจึงไม่จำเป็นต้องมีสิทธิ์เขียน
กระบวนการทั่วไปของการส่ง Intent เพื่อเข้าถึงผู้ให้บริการมีรายละเอียดอยู่ในคู่มือ
ข้อมูลเบื้องต้นเกี่ยวกับผู้ให้บริการเนื้อหาในส่วน "การเข้าถึงข้อมูลผ่าน Intent" การดำเนินการ ประเภท MIME และค่าข้อมูลที่ใช้สําหรับงานที่พร้อมใช้งานจะสรุปไว้ในตาราง 4 ส่วนค่าพิเศษที่คุณใช้กับ putExtra()
ได้จะแสดงอยู่ในเอกสารอ้างอิงสําหรับ ContactsContract.Intents.Insert
งาน | การทำงาน | ข้อมูล | ประเภท MIME | หมายเหตุ |
---|---|---|---|---|
เลือกรายชื่อติดต่อจากรายการ | ACTION_PICK |
ข้อใดข้อหนึ่งต่อไปนี้
|
ไม่ใช้ |
แสดงรายการรายชื่อติดต่อดิบหรือรายการข้อมูลจากรายชื่อติดต่อดิบ โดยขึ้นอยู่กับประเภท URI ของเนื้อหาที่คุณระบุ
โทรไปที่ |
แทรกรายชื่อติดต่อใหม่ในรูปแบบไฟล์ RAW | Insert.ACTION |
ไม่มี |
RawContacts.CONTENT_TYPE ประเภท MIME สำหรับชุดรายชื่อติดต่อดิบ
|
แสดงหน้าจอเพิ่มรายชื่อติดต่อของแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ ค่าพิเศษที่คุณเพิ่มลงใน Intent จะแสดงขึ้น หากส่งด้วย startActivityForResult() ระบบจะส่ง URI เนื้อหาของรายชื่อติดต่อแบบไฟล์ข้อมูลดิบซึ่งเพิ่มเข้ามาใหม่กลับไปยังonActivityResult() วิธีเรียกกลับของกิจกรรมในอาร์กิวเมนต์ Intent ในช่อง "data" หากต้องการรับค่า ให้เรียกใช้ getData()
|
แก้ไขรายชื่อติดต่อ | ACTION_EDIT |
CONTENT_LOOKUP_URI สำหรับรายชื่อติดต่อ กิจกรรมของเครื่องมือแก้ไขจะช่วยให้ผู้ใช้แก้ไขข้อมูลที่เชื่อมโยงกับรายชื่อติดต่อนี้ได้
|
Contacts.CONTENT_ITEM_TYPE รายชื่อติดต่อรายการเดียว |
แสดงหน้าจอแก้ไขรายชื่อติดต่อในแอปพลิเคชันรายชื่อติดต่อ ค่าพิเศษที่คุณเพิ่มลงใน Intent จะแสดงขึ้น เมื่อผู้ใช้คลิกเสร็จสิ้นเพื่อบันทึกการแก้ไข กิจกรรมของคุณจะกลับมาอยู่เบื้องหน้า |
แสดงเครื่องมือเลือกที่เพิ่มข้อมูลได้ด้วย | ACTION_INSERT_OR_EDIT |
ไม่มี |
CONTENT_ITEM_TYPE
|
Intent นี้จะแสดงหน้าจอเครื่องมือเลือกของแอปรายชื่อติดต่อเสมอ ผู้ใช้สามารถเลือกรายชื่อติดต่อที่จะแก้ไขหรือเพิ่มรายชื่อติดต่อใหม่ก็ได้ หน้าจอแก้ไขหรือเพิ่มจะปรากฏขึ้น ทั้งนี้ขึ้นอยู่กับตัวเลือกของผู้ใช้ และข้อมูลเสริมที่คุณส่งใน Intent จะแสดงขึ้น หากแอปแสดงข้อมูลติดต่อ เช่น อีเมลหรือหมายเลขโทรศัพท์ ให้ใช้ Intent นี้เพื่ออนุญาตให้ผู้ใช้เพิ่มข้อมูลลงในรายชื่อติดต่อที่มีอยู่
รายชื่อติดต่อ
หมายเหตุ: คุณไม่จําเป็นต้องส่งค่าชื่อในส่วนเพิ่มเติมของ Intent นี้เนื่องจากผู้ใช้จะเลือกชื่อที่มีอยู่หรือเพิ่มชื่อใหม่เสมอ นอกจากนี้ หากคุณส่งชื่อและผู้ใช้เลือกที่จะแก้ไข แอปรายชื่อติดต่อจะแสดงชื่อที่คุณส่งโดยเขียนทับค่าก่อนหน้า หากผู้ใช้ไม่สังเกตเห็นและบันทึกการแก้ไข ค่าเดิมจะหายไป |
แอปรายชื่อติดต่อของอุปกรณ์ไม่อนุญาตให้คุณลบข้อมูลติดต่อดิบหรือข้อมูลใดๆ ของแอปด้วยเจตนา หากต้องการลบรายชื่อติดต่อแบบไฟล์ดิบ ให้ใช้ ContentResolver.delete()
หรือ ContentProviderOperation.newDelete()
แทน
ข้อมูลโค้ดต่อไปนี้แสดงวิธีสร้างและส่ง Intent ที่แทรกรายชื่อติดต่อและข้อมูลใหม่แบบดิบ
Kotlin
// Gets values from the UI val name = contactNameEditText.text.toString() val phone = contactPhoneEditText.text.toString() val email = contactEmailEditText.text.toString() val company = companyName.text.toString() val jobtitle = jobTitle.text.toString() /* * Demonstrates adding data rows as an array list associated with the DATA key */ // Defines an array list to contain the ContentValues objects for each row val contactData = arrayListOf<ContentValues>() /* * Defines the raw contact row */ // Sets up the row as a ContentValues object val rawContactRow = ContentValues().apply { // Adds the account type and name to the row put(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.type) put(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.name) } // Adds the row to the array contactData.add(rawContactRow) /* * Sets up the phone number data row */ // Sets up the row as a ContentValues object val phoneRow = ContentValues().apply { // Specifies the MIME type for this data row (all data rows must be marked by their type) put(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Adds the phone number and its type to the row put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) } // Adds the row to the array contactData.add(phoneRow) /* * Sets up the email data row */ // Sets up the row as a ContentValues object val emailRow = ContentValues().apply { // Specifies the MIME type for this data row (all data rows must be marked by their type) put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Adds the email address and its type to the row put(ContactsContract.CommonDataKinds.Email.ADDRESS, email) } // Adds the row to the array contactData.add(emailRow) // Creates a new intent for sending to the device's contacts application val insertIntent = Intent(ContactsContract.Intents.Insert.ACTION).apply { // Sets the MIME type to the one expected by the insertion activity type = ContactsContract.RawContacts.CONTENT_TYPE // Sets the new contact name putExtra(ContactsContract.Intents.Insert.NAME, name) // Sets the new company and job title putExtra(ContactsContract.Intents.Insert.COMPANY, company) putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle) /* * Adds the array to the intent's extras. It must be a parcelable object in order to * travel between processes. The device's contacts app expects its key to be * Intents.Insert.DATA */ putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData) } // Send out the intent to start the device's contacts app in its add contact activity. startActivity(insertIntent)
Java
// Gets values from the UI String name = contactNameEditText.getText().toString(); String phone = contactPhoneEditText.getText().toString(); String email = contactEmailEditText.getText().toString(); String company = companyName.getText().toString(); String jobtitle = jobTitle.getText().toString(); // Creates a new intent for sending to the device's contacts application Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION); // Sets the MIME type to the one expected by the insertion activity insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE); // Sets the new contact name insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name); // Sets the new company and job title insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company); insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle); /* * Demonstrates adding data rows as an array list associated with the DATA key */ // Defines an array list to contain the ContentValues objects for each row ArrayList<ContentValues> contactData = new ArrayList<ContentValues>(); /* * Defines the raw contact row */ // Sets up the row as a ContentValues object ContentValues rawContactRow = new ContentValues(); // Adds the account type and name to the row rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.getType()); rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.getName()); // Adds the row to the array contactData.add(rawContactRow); /* * Sets up the phone number data row */ // Sets up the row as a ContentValues object ContentValues phoneRow = new ContentValues(); // Specifies the MIME type for this data row (all data rows must be marked by their type) phoneRow.put( ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE ); // Adds the phone number and its type to the row phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone); // Adds the row to the array contactData.add(phoneRow); /* * Sets up the email data row */ // Sets up the row as a ContentValues object ContentValues emailRow = new ContentValues(); // Specifies the MIME type for this data row (all data rows must be marked by their type) emailRow.put( ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE ); // Adds the email address and its type to the row emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email); // Adds the row to the array contactData.add(emailRow); /* * Adds the array to the intent's extras. It must be a parcelable object in order to * travel between processes. The device's contacts app expects its key to be * Intents.Insert.DATA */ insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData); // Send out the intent to start the device's contacts app in its add contact activity. startActivity(insertIntent);
ความสมบูรณ์ของข้อมูล
เนื่องจากที่เก็บข้อมูลรายชื่อติดต่อมีข้อมูลที่ละเอียดอ่อนและสำคัญซึ่งผู้ใช้คาดหวังว่าจะถูกต้องและเป็นปัจจุบัน ผู้ให้บริการรายชื่อติดต่อจึงมีกฎที่ชัดเจนเกี่ยวกับความสมบูรณ์ของข้อมูล คุณมีหน้าที่รับผิดชอบในการปฏิบัติตามกฎเหล่านี้เมื่อแก้ไขข้อมูลรายชื่อติดต่อ กฎที่สำคัญมีดังนี้
-
เพิ่มแถว
ContactsContract.CommonDataKinds.StructuredName
เสมอสำหรับทุกแถวContactsContract.RawContacts
ที่เพิ่ม -
แถว
ContactsContract.RawContacts
ที่ไม่มีแถวContactsContract.CommonDataKinds.StructuredName
ในตารางContactsContract.Data
อาจทำให้เกิดปัญหาระหว่างการรวม -
ลิงก์แถว
ContactsContract.Data
ใหม่กับแถวContactsContract.RawContacts
หลักเสมอ -
แถว
ContactsContract.Data
ที่ไม่ได้ลิงก์กับContactsContract.RawContacts
จะไม่ปรากฏในแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ และอาจทำให้เกิดปัญหากับอะแดปเตอร์การซิงค์ - เปลี่ยนข้อมูลสำหรับรายชื่อติดต่อดิบที่คุณเป็นเจ้าของเท่านั้น
- โปรดทราบว่าผู้ให้บริการข้อมูลติดต่อมักจะจัดการข้อมูลจากบัญชี/บริการออนไลน์หลายประเภท คุณต้องตรวจสอบว่าแอปพลิเคชันของคุณแก้ไขหรือลบเฉพาะข้อมูลของแถวที่เป็นของคุณ และแทรกเฉพาะข้อมูลที่มีประเภทและชื่อบัญชีที่คุณควบคุม
-
ใช้ค่าคงที่ที่กําหนดไว้ใน
ContactsContract
และคลาสย่อยของContactsContract
เสมอสําหรับหน่วยงาน URI ของเนื้อหา เส้นทาง URI ชื่อคอลัมน์ ประเภท MIME และค่าTYPE
- การใช้ค่าคงที่เหล่านี้จะช่วยหลีกเลี่ยงข้อผิดพลาด นอกจากนี้ คุณยังจะได้รับคำเตือนจากคอมไพเลอร์หากมีการเลิกใช้งานค่าคงที่
แถวข้อมูลที่กำหนดเอง
การสร้างและใช้ประเภท MIME ที่กําหนดเองจะช่วยให้คุณแทรก แก้ไข ลบ และเรียกข้อมูลแถวของคุณเองในตาราง ContactsContract.Data
ได้ แถวของคุณจะจำกัดให้ใช้คอลัมน์ที่กําหนดไว้ใน ContactsContract.DataColumns
แม้ว่าคุณจะแมปชื่อคอลัมน์เฉพาะประเภทของคุณเองกับชื่อคอลัมน์เริ่มต้นได้ ในแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ ระบบจะแสดงข้อมูลของแถว แต่แก้ไขหรือลบไม่ได้ และผู้ใช้จะเพิ่มข้อมูลอื่นไม่ได้ หากต้องการอนุญาตให้ผู้ใช้แก้ไขแถวข้อมูลที่กำหนดเอง คุณต้องระบุกิจกรรมตัวแก้ไขในแอปพลิเคชันของคุณเอง
หากต้องการแสดงข้อมูลที่กำหนดเอง ให้ระบุไฟล์ contacts.xml
ที่มีองค์ประกอบ <ContactsAccountType>
และองค์ประกอบย่อย <ContactsDataKind>
อย่างน้อย 1 รายการ ซึ่งอธิบายไว้อย่างละเอียดในส่วน <ContactsDataKind> element
ดูข้อมูลเพิ่มเติมเกี่ยวกับประเภท MIME ที่กําหนดเองได้จากคู่มือ สร้างผู้ให้บริการเนื้อหา
อะแดปเตอร์การซิงค์ของ Contacts Provider
ผู้ให้บริการรายชื่อติดต่อออกแบบมาเพื่อจัดการการซิงค์ข้อมูลรายชื่อติดต่อระหว่างอุปกรณ์กับบริการออนไลน์โดยเฉพาะ ซึ่งจะช่วยให้ผู้ใช้ดาวน์โหลดข้อมูลที่มีอยู่ไปยังอุปกรณ์เครื่องใหม่และอัปโหลดข้อมูลที่มีอยู่ไปยังบัญชีใหม่ได้ การซิงค์ยังช่วยให้ผู้ใช้มีข้อมูลล่าสุดอยู่เสมอ ไม่ว่าแหล่งที่มาของการเพิ่มและการเปลี่ยนแปลงจะมาจากที่ใดก็ตาม ข้อดีอีกอย่างหนึ่งของการซิงค์คือทำให้ข้อมูลรายชื่อติดต่อพร้อมใช้งานแม้ว่าอุปกรณ์จะไม่ได้เชื่อมต่อกับเครือข่ายก็ตาม
แม้ว่าคุณจะใช้การซิงค์ได้หลายวิธี แต่ระบบ Android มีเฟรมเวิร์กการซิงค์ปลั๊กอินที่ทำงานต่อไปนี้โดยอัตโนมัติ
- กำลังตรวจสอบความพร้อมใช้งานของเครือข่าย
- กำหนดเวลาและดำเนินการซิงค์ตามค่ากำหนดของผู้ใช้
- รีสตาร์ทการซิงค์ที่หยุดไปแล้ว
หากต้องการใช้เฟรมเวิร์กนี้ คุณต้องระบุปลั๊กอินอะแดปเตอร์การซิงค์ ตัวเชื่อมข้อมูลแต่ละรายการจะเชื่อมโยงกับบริการและผู้ให้บริการเนื้อหาเพียงรายเดียว แต่จัดการชื่อบัญชีหลายรายการสำหรับบริการเดียวกันได้ นอกจากนี้ เฟรมเวิร์กยังอนุญาตให้ใช้อะแดปเตอร์การซิงค์หลายรายการสําหรับบริการและผู้ให้บริการเดียวกัน
ซิงค์คลาสและไฟล์ของอะแดปเตอร์
คุณใช้อะแดปเตอร์การซิงค์เป็นคลาสย่อยของ AbstractThreadedSyncAdapter
และติดตั้งเป็นส่วนหนึ่งของแอปพลิเคชัน Android ระบบจะเรียนรู้เกี่ยวกับอะแดปเตอร์การซิงค์จากองค์ประกอบในไฟล์ Manifest ของแอปพลิเคชัน และจากไฟล์ XML พิเศษที่ไฟล์ Manifest ชี้ไป ไฟล์ XML จะกำหนดประเภทบัญชีสำหรับบริการออนไลน์และสิทธิ์ของผู้ให้บริการเนื้อหา ซึ่งจะระบุตัวระบุที่ไม่ซ้ำกันสำหรับอะแดปเตอร์ ตัวแปลงข้อมูลจะไม่ทำงานจนกว่าผู้ใช้จะเพิ่มบัญชีสำหรับประเภทบัญชีของตัวแปลงข้อมูลและเปิดใช้การซิงค์สำหรับผู้ให้บริการเนื้อหาที่ตัวแปลงข้อมูลซิงค์ด้วย เมื่อถึงจุดนั้น ระบบจะเริ่มจัดการอะแดปเตอร์ โดยเรียกใช้เมื่อจำเป็นเพื่อซิงค์ข้อมูลระหว่างผู้ให้บริการเนื้อหากับเซิร์ฟเวอร์
หมายเหตุ: การใช้ประเภทบัญชีเป็นส่วนหนึ่งของการระบุตัวตนของอะแดปเตอร์การซิงค์ช่วยให้ระบบตรวจหาและจัดกลุ่มอะแดปเตอร์การซิงค์ที่เข้าถึงบริการต่างๆ จากองค์กรเดียวกันได้ ตัวอย่างเช่น ตัวแปลงข้อมูลการซิงค์สำหรับบริการออนไลน์ของ Google ทั้งหมดมีประเภทบัญชี com.google
เดียวกัน เมื่อผู้ใช้เพิ่มบัญชี Google ลงในอุปกรณ์ ระบบจะแสดงอะแดปเตอร์การซิงค์ที่ติดตั้งไว้สำหรับบริการของ Google ทั้งหมดไว้ด้วยกัน โดยอะแดปเตอร์การซิงค์แต่ละรายการจะซิงค์กับผู้ให้บริการเนื้อหารายอื่นในอุปกรณ์
เนื่องจากบริการส่วนใหญ่กำหนดให้ผู้ใช้ต้องยืนยันตัวตนก่อนเข้าถึงข้อมูล ระบบ Android จึงมีเฟรมเวิร์กการตรวจสอบสิทธิ์ที่คล้ายกับเฟรมเวิร์กอะแดปเตอร์การซิงค์และมักใช้ร่วมกับเฟรมเวิร์กดังกล่าว เฟรมเวิร์กการตรวจสอบสิทธิ์ใช้โปรแกรมตรวจสอบสิทธิ์ปลั๊กอินที่เป็นคลาสย่อยของ AbstractAccountAuthenticator
โปรแกรมตรวจสอบสิทธิ์จะยืนยันตัวตนของผู้ใช้ในขั้นตอนต่อไปนี้
- รวบรวมชื่อ รหัสผ่าน หรือข้อมูลคล้ายกันของผู้ใช้ (ข้อมูลเข้าสู่ระบบของผู้ใช้)
- ส่งข้อมูลเข้าสู่ระบบไปยังบริการ
- ตรวจสอบคำตอบของบริการ
หากบริการยอมรับข้อมูลเข้าสู่ระบบ แอตทริบิวเตอร์จะจัดเก็บข้อมูลเข้าสู่ระบบไว้ใช้ภายหลังได้ AccountManager
สามารถให้สิทธิ์เข้าถึงโทเค็นการให้สิทธิ์ที่โปรแกรมตรวจสอบสิทธิ์รองรับและเลือกที่จะแสดง เช่น โทเค็นการให้สิทธิ์ OAuth2 เนื่องจากเฟรมเวิร์กโปรแกรมตรวจสอบสิทธิ์แบบปลั๊กอิน
แม้ว่าการตรวจสอบสิทธิ์จะไม่จำเป็น แต่บริการรายชื่อติดต่อส่วนใหญ่จะใช้การตรวจสอบสิทธิ์ อย่างไรก็ตาม คุณไม่จำเป็นต้องใช้เฟรมเวิร์กการตรวจสอบสิทธิ์ของ Android เพื่อดำเนินการตรวจสอบสิทธิ์
การติดตั้งใช้งานอะแดปเตอร์การซิงค์
หากต้องการใช้อะแดปเตอร์การซิงค์สำหรับผู้ให้บริการรายชื่อติดต่อ ให้เริ่มต้นด้วยการสร้างแอปพลิเคชัน Android ที่มีสิ่งต่อไปนี้
-
คอมโพเนนต์
Service
ที่ตอบสนองต่อคําขอจากระบบให้เชื่อมโยงกับอะแดปเตอร์การซิงค์ -
เมื่อระบบต้องการเรียกใช้การซิงค์ ระบบจะเรียกใช้เมธอด
onBind()
ของบริการเพื่อรับIBinder
สำหรับอะแดปเตอร์การซิงค์ ซึ่งช่วยให้ระบบเรียกใช้เมธอดของอะแดปเตอร์ข้ามกระบวนการได้ -
อะแดปเตอร์การซิงค์จริงซึ่งติดตั้งใช้งานเป็นคลาสย่อยที่เฉพาะเจาะจงของ
AbstractThreadedSyncAdapter
-
คลาสนี้จะดาวน์โหลดข้อมูลจากเซิร์ฟเวอร์ อัปโหลดข้อมูลจากอุปกรณ์ และแก้ไขข้อขัดแย้ง งานหลักของอะแดปเตอร์จะดำเนินการในเมธอด
onPerformSync()
คลาสนี้ต้องสร้างอินสแตนซ์เป็น Singleton -
คลาสย่อยของ
Application
-
คลาสนี้ทำหน้าที่เป็นโรงงานสำหรับซิงโครไนซ์อะแดปเตอร์แบบ Singleton ใช้เมธอด
onCreate()
เพื่อสร้างอินสแตนซ์ของอะแดปเตอร์การซิงค์ และระบุเมธอด "getter" แบบคงที่เพื่อแสดงผล Singleton ไปยังเมธอดonBind()
ของบริการอะแดปเตอร์การซิงค์ -
ไม่บังคับ: คอมโพเนนต์
Service
ที่ตอบสนองต่อคําขอจากระบบสําหรับการตรวจสอบสิทธิ์ผู้ใช้ -
AccountManager
เริ่มบริการนี้เพื่อเริ่มกระบวนการตรวจสอบสิทธิ์ เมธอดonCreate()
ของบริการจะสร้างอินสแตนซ์ออบเจ็กต์โปรแกรมตรวจสอบสิทธิ์ เมื่อระบบต้องการตรวจสอบสิทธิ์บัญชีผู้ใช้สำหรับอะแดปเตอร์การซิงค์ของแอปพลิเคชัน ระบบจะเรียกใช้เมธอดonBind()
ของบริการเพื่อรับIBinder
สำหรับโปรแกรมตรวจสอบสิทธิ์ ซึ่งช่วยให้ระบบเรียกใช้เมธอดของโปรแกรมตรวจสอบสิทธิ์ข้ามกระบวนการได้ -
ไม่บังคับ: คลาสย่อยที่เฉพาะเจาะจงของ
AbstractAccountAuthenticator
ที่จัดการคําขอการตรวจสอบสิทธิ์ -
คลาสนี้มีเมธอดที่
AccountManager
เรียกใช้เพื่อตรวจสอบสิทธิ์ข้อมูลเข้าสู่ระบบของผู้ใช้กับเซิร์ฟเวอร์ รายละเอียดของกระบวนการตรวจสอบสิทธิ์จะแตกต่างกันไปอย่างมาก โดยขึ้นอยู่กับเทคโนโลยีเซิร์ฟเวอร์ที่ใช้ คุณควรอ่านเอกสารประกอบของซอฟต์แวร์เซิร์ฟเวอร์เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับการตรวจสอบสิทธิ์ - ไฟล์ XML ที่กําหนดอะแดปเตอร์การซิงค์และผู้ตรวจสอบสิทธิ์ให้กับระบบ
-
คอมโพเนนต์บริการโปรแกรมซิงค์และโปรแกรมตรวจสอบสิทธิ์ที่อธิบายไว้ก่อนหน้านี้จะกำหนดไว้ในองค์ประกอบ
<service>
ในไฟล์ Manifest ของแอปพลิเคชัน องค์ประกอบเหล่านี้มีองค์ประกอบย่อย<meta-data>
ที่ระบุข้อมูลเฉพาะแก่ระบบ-
องค์ประกอบ
<meta-data>
สำหรับบริการอะแดปเตอร์การซิงค์ชี้ไปยังไฟล์ XMLres/xml/syncadapter.xml
ไฟล์นี้จะระบุ URI สำหรับเว็บเซอร์วิสที่จะซิงค์กับผู้ให้บริการ Contacts และประเภทบัญชีสำหรับเว็บเซอร์วิส -
ไม่บังคับ: องค์ประกอบ
<meta-data>
สำหรับโปรแกรมตรวจสอบสิทธิ์จะชี้ไปยังไฟล์ XMLres/xml/authenticator.xml
ไฟล์นี้จะระบุประเภทบัญชีที่ Authenticator นี้รองรับ รวมถึงทรัพยากร 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
- สตริงข้อความที่มีเวลาที่แทรกหรืออัปเดตรายการสตรีมในรูปแบบมิลลิวินาทีนับจากจุดเริ่มต้น แอปพลิเคชันที่แทรกหรืออัปเดตรายการสตรีมมีหน้าที่รับผิดชอบในการดูแลรักษาคอลัมน์นี้ ผู้ให้บริการรายชื่อติดต่อจะไม่ดูแลรักษาคอลัมน์นี้โดยอัตโนมัติ
หากต้องการแสดงข้อมูลระบุรายการสตรีม ให้ใช้ android.provider.ContactsContract.StreamItemsColumns#RES_ICON, android.provider.ContactsContract.StreamItemsColumns#RES_LABEL และ android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE เพื่อลิงก์กับทรัพยากรในแอปพลิเคชัน
ตาราง android.provider.ContactsContract.StreamItems ยังมีคอลัมน์ android.provider.ContactsContract.StreamItemsColumns#SYNC1 ถึง android.provider.ContactsContract.StreamItemsColumns#SYNC4 สําหรับใช้กับอะแดปเตอร์การซิงค์โดยเฉพาะ
รูปภาพในสตรีมโซเชียล
ตาราง android.provider.ContactsContract.StreamItemPhotos จัดเก็บรูปภาพที่เชื่อมโยงกับรายการสตรีม คอลัมน์ android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID ของตารางจะลิงก์กับค่าในคอลัมน์ _ID
ของตาราง android.provider.ContactsContract.StreamItems ระบบจะจัดเก็บข้อมูลอ้างอิงรูปภาพไว้ในตารางในคอลัมน์ต่อไปนี้
- คอลัมน์ android.provider.ContactsContract.StreamItemPhotos#PHOTO (BLOB)
- การนำเสนอรูปภาพในรูปแบบไบนารี ซึ่งผู้ให้บริการจะปรับขนาดเพื่อจัดเก็บและแสดง คอลัมน์นี้มีไว้เพื่อใช้งานร่วมกับผู้ให้บริการรายชื่อติดต่อเวอร์ชันเก่าที่ใช้สำหรับจัดเก็บรูปภาพ อย่างไรก็ตาม ในเวอร์ชันปัจจุบัน คุณไม่ควรใช้คอลัมน์นี้เพื่อจัดเก็บรูปภาพ แต่ให้ใช้ android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID หรือ android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI (ทั้ง 2 รายการอธิบายไว้ในหัวข้อต่อไปนี้) เพื่อจัดเก็บรูปภาพในไฟล์ ตอนนี้คอลัมน์นี้มีภาพขนาดย่อของรูปภาพซึ่งพร้อมให้อ่าน
- android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID
-
ตัวระบุตัวเลขของรูปภาพสำหรับรายชื่อติดต่อแบบไฟล์ดิบ ต่อท้ายค่านี้กับค่าคงที่
DisplayPhoto.CONTENT_URI
เพื่อรับ URI เนื้อหาที่ชี้ไปยังไฟล์รูปภาพไฟล์เดียว จากนั้นเรียกใช้openAssetFileDescriptor()
เพื่อรับแฮนเดิลของไฟล์รูปภาพ - android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI
-
URI ของเนื้อหาที่ชี้ไปยังไฟล์รูปภาพโดยตรงสำหรับรูปภาพที่แสดงโดยแถวนี้
โทรหา
openAssetFileDescriptor()
ด้วย URI นี้เพื่อรับแฮนเดิลของไฟล์รูปภาพ
การใช้ตารางสตรีมโซเชียล
ตารางเหล่านี้ทำงานเหมือนกับตารางหลักอื่นๆ ในผู้ให้บริการรายชื่อติดต่อ ยกเว้นข้อต่อไปนี้
- ตารางเหล่านี้ต้องมีสิทธิ์เข้าถึงเพิ่มเติม หากต้องการอ่านจากแหล่งข้อมูลดังกล่าว แอปพลิเคชันของคุณต้องมีสิทธิ์ android.Manifest.permission#READ_SOCIAL_STREAM หากต้องการแก้ไข แอปพลิเคชันของคุณต้องมีสิทธิ์ android.Manifest.permission#WRITE_SOCIAL_STREAM
-
สำหรับตาราง android.provider.ContactsContract.StreamItems จำนวนแถวที่จัดเก็บสำหรับรายชื่อติดต่อดิบแต่ละรายการมีขีดจำกัด เมื่อถึงขีดจํากัดนี้ ผู้ให้บริการ Contacts จะจัดสรรพื้นที่ว่างสําหรับแถวรายการสตรีมใหม่โดยลบแถวที่มี android.provider.ContactsContract.StreamItemsColumns#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 ซึ่งมีแถวรูปภาพสำหรับรายการสตรีมรายการเดียว
การโต้ตอบในสตรีมโซเชียล
ข้อมูลสตรีมโซเชียลที่จัดการโดยผู้ให้บริการรายชื่อติดต่อร่วมกับแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์เป็นวิธีที่มีประสิทธิภาพในการเชื่อมต่อระบบเครือข่ายสังคมกับรายชื่อติดต่อที่มีอยู่ ฟีเจอร์ต่อไปนี้พร้อมใช้งาน
- การซิงค์บริการเครือข่ายโซเชียลกับผู้ให้บริการ Contacts ด้วยอะแดปเตอร์การซิงค์จะช่วยให้คุณเรียกดูกิจกรรมล่าสุดของรายชื่อติดต่อของผู้ใช้และจัดเก็บไว้ในตาราง android.provider.ContactsContract.StreamItems และ android.provider.ContactsContract.StreamItemPhotos เพื่อใช้ภายหลังได้
- นอกจากการซิงค์ปกติแล้ว คุณยังเรียกใช้อะแดปเตอร์การซิงค์เพื่อดึงข้อมูลเพิ่มเติมได้เมื่อผู้ใช้เลือกรายชื่อติดต่อเพื่อดู ซึ่งจะช่วยให้อะแดปเตอร์การซิงค์ดึงข้อมูลรูปภาพความละเอียดสูงและรายการสตรีมล่าสุดของผู้ติดต่อได้
- การลงทะเบียนการแจ้งเตือนกับแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์และผู้ให้บริการรายชื่อติดต่อจะช่วยให้คุณรับ Intent ได้เมื่อมีการดูรายชื่อติดต่อ และอัปเดตสถานะรายชื่อติดต่อจากบริการของคุณได้ วิธีนี้อาจเร็วกว่าและใช้แบนด์วิดท์น้อยกว่าการซิงค์ทั้งหมดด้วยอะแดปเตอร์การซิงค์
- ผู้ใช้สามารถเพิ่มรายชื่อติดต่อไปยังบริการเครือข่ายสังคมขณะดูรายชื่อติดต่อในแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์ คุณเปิดใช้ฟีเจอร์นี้ได้ด้วยฟีเจอร์ "เชิญรายชื่อติดต่อ" ซึ่งเปิดใช้ด้วยการรวมกิจกรรมที่เพิ่มรายชื่อติดต่อที่มีอยู่ลงในเครือข่าย และไฟล์ XML ที่ระบุรายละเอียดแอปพลิเคชันของคุณให้กับแอปพลิเคชันรายชื่อติดต่อของอุปกรณ์และผู้ให้บริการรายชื่อติดต่อ
การซิงค์รายการสตรีมกับผู้ให้บริการรายชื่อติดต่อเป็นประจำจะเหมือนกับการซิงค์อื่นๆ ดูข้อมูลเพิ่มเติมเกี่ยวกับการซิงค์ได้ที่ส่วนอะแดปเตอร์การซิงค์ของผู้ให้บริการรายชื่อติดต่อ การลงทะเบียนการแจ้งเตือนและการเชิญผู้ติดต่อจะอยู่ใน 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
คือชื่อคลาสแบบเต็มที่สมบูรณ์ของกิจกรรมที่ควรได้รับ Intent ค่า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 ที่อนุญาตให้ผู้ใช้เชิญรายชื่อติดต่อให้เข้าร่วมโซเชียลเน็ตเวิร์ก แจ้งให้ผู้ใช้ทราบเมื่อสตรีมโซเชียลเน็ตเวิร์กมีการอัปเดต และอื่นๆ
โปรดทราบว่าแอตทริบิวต์ของ <ContactsAccountType>
ไม่จำเป็นต้องมีคำนำหน้าแอตทริบิวต์ android:
แอตทริบิวต์:
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
ฟีเจอร์เพิ่มเติมของ Contacts Provider
นอกเหนือจากฟีเจอร์หลักที่อธิบายไว้ในส่วนก่อนหน้านี้ ผู้ให้บริการรายชื่อติดต่อยังมีฟีเจอร์ที่มีประโยชน์ต่อไปนี้สำหรับการทำงานกับข้อมูลรายชื่อติดต่อ
- กลุ่มรายชื่อติดต่อ
- ฟีเจอร์รูปภาพ
กลุ่มรายชื่อติดต่อ
ผู้ให้บริการข้อมูลติดต่อสามารถเลือกติดป้ายกำกับคอลเล็กชันรายชื่อติดต่อที่เกี่ยวข้องด้วยข้อมูลกลุ่ม หากเซิร์ฟเวอร์ที่เชื่อมโยงกับบัญชีผู้ใช้ต้องการดูแลรักษากลุ่ม แอดอะปเตอร์การซิงค์สำหรับประเภทบัญชีของบัญชีควรโอนข้อมูลกลุ่มระหว่างผู้ให้บริการ Contacts กับเซิร์ฟเวอร์ เมื่อผู้ใช้เพิ่มรายชื่อติดต่อใหม่ลงในเซิร์ฟเวอร์ แล้วใส่รายชื่อติดต่อนี้ไว้ในกลุ่มใหม่ แอดอะแดปเตอร์การซิงค์ต้องเพิ่มกลุ่มใหม่ลงในตาราง ContactsContract.Groups
ระบบจะจัดเก็บกลุ่มที่รายชื่อติดต่อแบบไฟล์ข้อมูลดิบอยู่ไว้ในตาราง ContactsContract.Data
โดยใช้ประเภท MIME ContactsContract.CommonDataKinds.GroupMembership
หากคุณออกแบบอะแดปเตอร์การซิงค์ที่จะเพิ่มข้อมูลรายชื่อติดต่อดิบจากเซิร์ฟเวอร์ไปยังผู้ให้บริการ Contacts และไม่ได้ใช้กลุ่ม คุณจะต้องบอกผู้ให้บริการให้แสดงข้อมูลของคุณ ในโค้ดที่ทำงานเมื่อผู้ใช้เพิ่มบัญชีลงในอุปกรณ์ ให้อัปเดตแถว ContactsContract.Settings
ที่ผู้ให้บริการข้อมูลติดต่อเพิ่มสำหรับบัญชี ในแถวนี้ ให้ตั้งค่าของคอลัมน์ Settings.UNGROUPED_VISIBLE
เป็น 1 เมื่อดำเนินการดังกล่าว ผู้ให้บริการรายชื่อติดต่อจะแสดงข้อมูลรายชื่อติดต่อของคุณเสมอ แม้ว่าคุณจะไม่ได้ใช้กลุ่มก็ตาม
รูปภาพผู้ติดต่อ
ตาราง ContactsContract.Data
จัดเก็บรูปภาพเป็นแถวที่มีประเภท MIME
Photo.CONTENT_ITEM_TYPE
คอลัมน์ CONTACT_ID
ของแถวจะลิงก์กับคอลัมน์ _ID
ของรายชื่อติดต่อดิบที่เป็นของแถวนั้น
คลาส ContactsContract.Contacts.Photo
จะกำหนดตารางย่อยของ ContactsContract.Contacts
ซึ่งมีข้อมูลรูปภาพสำหรับรูปภาพหลักของผู้ติดต่อ ซึ่งเป็นรูปภาพหลักของผู้ติดต่อ RAW หลัก ในทํานองเดียวกัน คลาส ContactsContract.RawContacts.DisplayPhoto
จะกําหนดตารางย่อยของ ContactsContract.RawContacts
ที่มีข้อมูลรูปภาพสําหรับรูปภาพหลักของรายชื่อติดต่อดิบ
เอกสารอ้างอิงสำหรับ ContactsContract.Contacts.Photo
และ ContactsContract.RawContacts.DisplayPhoto
มีตัวอย่างการดึงข้อมูลรูปภาพ ไม่มีคลาสอำนวยความสะดวกสำหรับการดึงข้อมูลภาพขนาดย่อหลักของผู้ติดต่อแบบไฟล์ดิบ แต่คุณสามารถส่งการค้นหาไปยังตาราง ContactsContract.Data
โดยเลือกคอลัมน์ _ID
, Photo.CONTENT_ITEM_TYPE
และ IS_PRIMARY
ของผู้ติดต่อแบบไฟล์ดิบเพื่อค้นหาแถวรูปภาพหลักของผู้ติดต่อแบบไฟล์ดิบ
ข้อมูลสตรีมโซเชียลของบุคคลหนึ่งอาจรวมถึงรูปภาพด้วย ระบบจะจัดเก็บข้อมูลเหล่านี้ไว้ในตาราง android.provider.ContactsContract.StreamItemPhotos ซึ่งอธิบายไว้อย่างละเอียดในส่วนรูปภาพสตรีมโซเชียล