ผู้ให้บริการเนื้อหาจะจัดการสิทธิ์เข้าถึงที่เก็บข้อมูลกลาง คุณใช้
เป็นผู้ให้บริการคลาวด์อย่างน้อยหนึ่งคลาสในแอปพลิเคชัน Android พร้อมด้วยองค์ประกอบใน
ไฟล์ Manifest หนึ่งในคลาสของคุณใช้คลาสย่อยของ
ContentProvider
ซึ่งเป็นอินเทอร์เฟซระหว่างผู้ให้บริการของคุณกับ
แอปพลิเคชันอื่นๆ
แม้ว่าผู้ให้บริการเนื้อหาจะมีไว้เพื่อให้ข้อมูล คุณสามารถมีกิจกรรมในแอปพลิเคชันที่ช่วยให้ผู้ใช้ ค้นหาและแก้ไขข้อมูลที่จัดการโดยผู้ให้บริการ
หน้านี้ประกอบด้วยขั้นตอนพื้นฐานในการสร้างผู้ให้บริการเนื้อหาและรายชื่อ API ต่างๆ ที่ใช้ได้
ก่อนเริ่มสร้าง
ก่อนที่จะเริ่มสร้างผู้ให้บริการ ให้พิจารณาสิ่งต่อไปนี้
-
ตัดสินใจว่าคุณต้องการผู้ให้บริการเนื้อหาหรือไม่ คุณต้องสร้างเนื้อหา
ผู้ให้บริการเครือข่าย หากคุณต้องการให้บริการฟีเจอร์ต่อไปนี้อย่างน้อย 1 อย่าง
- คุณต้องการนำเสนอข้อมูลหรือไฟล์ที่ซับซ้อนให้แก่แอปพลิเคชันอื่น
- คุณต้องการให้ผู้ใช้คัดลอกข้อมูลที่ซับซ้อนจากแอปไปยังแอปอื่นๆ
- คุณต้องการให้คำแนะนำการค้นหาที่กำหนดเองโดยใช้กรอบการค้นหา
- คุณต้องการเปิดเผยข้อมูลแอปพลิเคชันไปยังวิดเจ็ต
- คุณต้องการใช้
AbstractThreadedSyncAdapter
CursorAdapter
หรือCursorLoader
ใหม่
คุณไม่จำเป็นต้องมีผู้ให้บริการเพื่อใช้ฐานข้อมูลหรือข้อมูลประเภทอื่นๆ พื้นที่เก็บข้อมูลถาวร หากการใช้งานนั้นอยู่ภายในแอปพลิเคชันของคุณทั้งหมด และคุณไม่จำเป็นต้องมี ฟีเจอร์ก่อนหน้านี้แสดงอยู่ อย่างไรก็ตาม คุณสามารถ ใช้ระบบจัดเก็บข้อมูลระบบใดระบบหนึ่งตามที่อธิบายไว้ใน ภาพรวมของพื้นที่เก็บข้อมูลและไฟล์
- หากคุณยังไม่ได้อ่าน โปรดอ่าน ข้อมูลเบื้องต้นเกี่ยวกับผู้ให้บริการเนื้อหาเพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับผู้ให้บริการและวิธีการทำงาน
ถัดไป ให้ทำตามขั้นตอนต่อไปนี้เพื่อสร้างผู้ให้บริการ
-
ออกแบบพื้นที่เก็บข้อมูลดิบสำหรับข้อมูลของคุณ ผู้ให้บริการเนื้อหานำเสนอข้อมูลด้วย 2 วิธีดังนี้
- ข้อมูลไฟล์
- ข้อมูลที่โดยปกติแล้วจะอยู่ในไฟล์ เช่น รูปภาพ เสียง หรือวิดีโอ จัดเก็บไฟล์ไว้ในที่ส่วนตัวของแอปพลิเคชัน พื้นที่ทำงาน ในการตอบกลับคำขอไฟล์จากแอปพลิเคชันอื่น สามารถเสนอแฮนเดิลไฟล์ได้
- "มีโครงสร้าง" ข้อมูล
- ข้อมูลที่โดยปกติแล้วจะอยู่ในฐานข้อมูล อาร์เรย์ หรือโครงสร้างที่คล้ายกัน จัดเก็บข้อมูลในแบบฟอร์มที่ใช้ร่วมกับตารางแถวและคอลัมน์ได้ แถว แสดงถึงเอนทิตี เช่น บุคคลหรือสินค้าในสินค้าคงคลัง คอลัมน์แสดงถึง ข้อมูลบางอย่างสำหรับเอนทิตี เช่น ชื่อบุคคลหรือราคาสินค้า วิธีทั่วไปในการ จัดเก็บข้อมูลประเภทนี้อยู่ในฐานข้อมูล SQLite แต่คุณสามารถใช้ พื้นที่เก็บข้อมูลถาวร หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับประเภทพื้นที่เก็บข้อมูลที่มีให้ใช้งานใน ระบบ Android โปรดดู ออกแบบพื้นที่เก็บข้อมูล
-
กำหนดการนำชั้นเรียน
ContentProvider
ไปใช้อย่างเป็นรูปธรรมและ วิธีการที่จำเป็น คลาสนี้เป็นอินเทอร์เฟซระหว่างข้อมูลของคุณและส่วนอื่นๆ ระบบ Android ดูข้อมูลเพิ่มเติมเกี่ยวกับชั้นเรียนนี้ได้ที่ ใช้คลาส ContentProvider - กำหนดสตริงสิทธิ์ของผู้ให้บริการ, URI เนื้อหา และชื่อคอลัมน์ หากคุณต้องการ แอปพลิเคชันของผู้ให้บริการในการจัดการกับ Intent ต้องกำหนดการดำเนินการของ Intent ข้อมูลเพิ่มเติม และแฟล็ก รวมถึงกำหนดสิทธิ์ที่คุณต้องใช้สำหรับแอปพลิเคชันที่ต้องการ เพื่อเข้าถึงข้อมูลของคุณ ลองกำหนดค่าทั้งหมดนี้เป็นค่าคงที่ใน ชั้นสัญญาแยกต่างหาก คุณแสดงชั้นเรียนนี้แก่นักพัฒนาซอฟต์แวร์คนอื่นๆ ได้ในภายหลัง สำหรับข้อมูลเพิ่มเติม เกี่ยวกับ URI เนื้อหา โปรดดู ออกแบบ URI เนื้อหา สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ Intent โปรดดู Intent และการเข้าถึงข้อมูล
-
เพิ่มส่วนที่ไม่บังคับอื่นๆ เช่น ข้อมูลตัวอย่างหรือการใช้งาน
จาก
AbstractThreadedSyncAdapter
ที่สามารถซิงค์ข้อมูลระหว่าง ผู้ให้บริการและข้อมูลในระบบคลาวด์
ออกแบบพื้นที่เก็บข้อมูล
ผู้ให้บริการเนื้อหาคืออินเทอร์เฟซสําหรับข้อมูลที่บันทึกไว้ในรูปแบบที่มีโครงสร้าง ก่อนสร้าง อินเทอร์เฟซ ในการตัดสินใจเลือกวิธีการจัดเก็บข้อมูล คุณสามารถจัดเก็บข้อมูลในรูปแบบใดก็ได้ ที่ชอบ จากนั้นออกแบบอินเทอร์เฟซให้อ่านและเขียนข้อมูลตามที่ต้องการ
เทคโนโลยีพื้นที่เก็บข้อมูลบางส่วนที่มีใน Android มีดังนี้
- ถ้าคุณใช้ข้อมูลที่มีโครงสร้าง ให้พิจารณาใช้ฐานข้อมูลเชิงสัมพันธ์ เป็น SQLite หรือที่เก็บข้อมูลคีย์-ค่าที่ไม่ใช่เชิงสัมพันธ์ เช่น LevelDB หากคุณกำลังทำงาน กับข้อมูลที่ไม่มีโครงสร้าง เช่น สื่อเสียง รูปภาพ หรือวิดีโอ แล้วลองพิจารณาการจัดเก็บ เป็นไฟล์ข้อมูล คุณสามารถเลือกใช้พื้นที่หลายประเภทร่วมกันเพื่อแสดงพื้นที่เก็บข้อมูล โดยใช้ผู้ให้บริการเนื้อหารายเดียว หากจำเป็น
-
ระบบ Android สามารถโต้ตอบกับไลบรารีความต่อเนื่องของห้อง ซึ่ง
ให้สิทธิ์เข้าถึง API สำหรับฐานข้อมูล SQLite ที่ผู้ให้บริการของ Android เอง
ใช้ในการจัดเก็บข้อมูลแบบตาราง วิธีสร้างฐานข้อมูลโดยใช้
ไลบรารี, สร้างอินสแตนซ์คลาสย่อยของ
RoomDatabase
ตามที่อธิบายไว้ใน บันทึกข้อมูลในฐานข้อมูลในเครื่องโดยใช้ห้องแชทคุณไม่ต้องใช้ฐานข้อมูลเพื่อใช้ที่เก็บ ผู้ให้บริการ ปรากฏภายนอกเป็นชุดตาราง คล้ายกับฐานข้อมูลเชิงสัมพันธ์ แต่ ไม่ใช่ข้อกำหนดสำหรับการใช้งานภายในของผู้ให้บริการ
- Android มี API ต่างๆ เกี่ยวกับไฟล์สำหรับการจัดเก็บข้อมูลไฟล์ หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับพื้นที่เก็บข้อมูลไฟล์ โปรดอ่าน ภาพรวมของพื้นที่เก็บข้อมูลและไฟล์ หากคุณ การออกแบบผู้ให้บริการที่ให้ข้อมูลเกี่ยวกับสื่อ เช่น เพลงหรือวิดีโอ คุณสามารถ มีผู้ให้บริการที่รวมข้อมูลตารางและไฟล์เข้าด้วยกัน
- ในบางกรณี คุณอาจได้ประโยชน์จากการใช้ผู้ให้บริการเนื้อหามากกว่า 1 ราย แอปพลิเคชันเดียว ตัวอย่างเช่น คุณอาจต้องการแชร์ข้อมูลบางอย่างกับวิดเจ็ตโดยใช้ ผู้ให้บริการเนื้อหารายหนึ่ง และแสดงชุดข้อมูลคนละชุดเพื่อแชร์กับผู้ให้บริการเนื้อหารายอื่น แอปพลิเคชัน
-
สำหรับการทำงานกับข้อมูลบนเครือข่าย ให้ใช้คลาสใน
java.net
และandroid.net
คุณยังสามารถซิงค์ข้อมูลสำหรับเครือข่ายกับข้อมูลในเครื่องได้ด้วย จัดเก็บข้อมูล เช่น ฐานข้อมูล แล้วนำเสนอข้อมูลเป็นตารางหรือไฟล์
หมายเหตุ: หากทำการเปลี่ยนแปลงที่เก็บในลักษณะดังกล่าว เข้ากันได้แบบย้อนหลัง คุณต้องทำเครื่องหมายที่เก็บด้วยเวอร์ชันใหม่ หมายเลข คุณยังต้องเพิ่มหมายเลขเวอร์ชันของแอปที่ จะใช้ผู้ให้บริการเนื้อหารายใหม่ การเปลี่ยนแปลงนี้จะป้องกันไม่ให้ระบบ ดาวน์เกรดจากการทำให้ระบบขัดข้องเมื่อพยายามติดตั้งใหม่อีกครั้ง แอปที่มีผู้ให้บริการเนื้อหาที่ใช้ร่วมกันไม่ได้
ข้อควรพิจารณาในการออกแบบข้อมูล
เคล็ดลับสำหรับการออกแบบโครงสร้างข้อมูลของผู้ให้บริการมีดังนี้
-
ข้อมูลตารางต้องมี "คีย์หลัก" เสมอ ที่ผู้ให้บริการเก็บไว้
เป็นค่าตัวเลขที่ไม่ซ้ำกันสำหรับแต่ละแถว คุณสามารถใช้ค่านี้เพื่อลิงก์แถวกับ
แถวในตารางอื่นๆ (ใช้เป็น "กุญแจต่างประเทศ") แม้ว่าคุณจะสามารถใช้ชื่อใดก็ได้
สำหรับคอลัมน์นี้ การใช้
BaseColumns._ID
ถือว่าดีที่สุด เนื่องจากการลิงก์ผลลัพธ์การค้นหาของผู้ให้บริการกับListView
กำหนดให้คอลัมน์ใดคอลัมน์หนึ่งมีชื่อมีชื่อ_ID
-
หากคุณต้องการใส่ภาพบิตแมปหรือข้อมูลที่เกี่ยวกับไฟล์อื่นๆ ที่มีขนาดใหญ่มาก ให้จัดเก็บ
ข้อมูลในไฟล์ แล้วส่งข้อมูลนั้นโดยอ้อม แทนที่จะเก็บไว้ในไฟล์โดยตรง
หากคุณทำเช่นนี้ คุณต้องแจ้งผู้ใช้ของผู้ให้บริการว่าจำเป็นต้องใช้
ContentResolver
วิธีเข้าถึงข้อมูล -
ใช้ประเภทข้อมูลไบนารีที่มีขนาดใหญ่ (BLOB) เพื่อจัดเก็บข้อมูลที่มีขนาดแตกต่างกันไปหรือมีจำนวน
โครงสร้างที่หลากหลาย ตัวอย่างเช่น คุณสามารถใช้คอลัมน์ BLOB เพื่อจัดเก็บ
บัฟเฟอร์โปรโตคอล หรือ
โครงสร้าง JSON
นอกจากนี้ คุณยังใช้ BLOB เพื่อใช้ตารางที่ไม่อิงตามสคีมาได้ด้วย ใน ตารางประเภทนี้ คุณกำหนดคอลัมน์คีย์หลัก คอลัมน์ประเภท MIME และ คอลัมน์ทั่วไปในรูปแบบ BLOB มีการระบุความหมายของข้อมูลในคอลัมน์ BLOB ด้วยค่าในคอลัมน์ประเภท MIME ซึ่งจะช่วยให้คุณจัดเก็บแถวประเภทต่างๆ ไว้ใน ตารางเดียวกัน "ข้อมูล" ของผู้ให้บริการรายชื่อติดต่อ โต๊ะ
ContactsContract.Data
เป็นตัวอย่างของสคีมาที่ไม่อิงตามสคีมา
ออกแบบ URI เนื้อหา
URL เนื้อหาคือ URI ที่ระบุข้อมูลในผู้ให้บริการ URI เนื้อหาประกอบด้วย
ชื่อสัญลักษณ์ของผู้ให้บริการทั้งหมด (หน่วยงานของผู้ให้บริการ) และ
ชื่อที่ชี้ไปยังตารางหรือไฟล์ (เส้นทาง) ส่วน ID ที่ไม่บังคับจะชี้ไปยัง
แต่ละแถวในตาราง วิธีการเข้าถึงข้อมูลทุกวิธีของ
ContentProvider
มี URI เนื้อหาเป็นอาร์กิวเมนต์ ซึ่งช่วยให้คุณ
กำหนดตาราง แถว หรือไฟล์ที่ต้องการเข้าถึง
สำหรับข้อมูลเกี่ยวกับ URI เนื้อหา โปรดดู ข้อมูลเบื้องต้นเกี่ยวกับผู้ให้บริการเนื้อหา
ออกแบบหน่วยงาน
ผู้ให้บริการมักจะมีสิทธิ์เดียว ซึ่งทำหน้าที่เป็นชื่อภายใน Android ของตน ถึง หลีกเลี่ยงการขัดแย้งกับผู้ให้บริการรายอื่น ใช้การเป็นเจ้าของโดเมนอินเทอร์เน็ต (ในทางกลับกัน) เป็นพื้นฐานของอำนาจของผู้ให้บริการ เนื่องจากคำแนะนำนี้เป็นจริงสำหรับ Android เช่นกัน ชื่อแพ็กเกจ คุณสามารถกำหนดหน้าที่ของผู้ให้บริการของคุณเป็นส่วนขยายของชื่อได้ ของหีบห่อที่มีผู้ให้บริการรายนั้น
ตัวอย่างเช่น หากชื่อแพ็กเกจ Android ของคุณคือ
com.example.<appname>
ให้เวลาผู้ให้บริการ
หน่วยงาน com.example.<appname>.provider
ออกแบบโครงสร้างเส้นทาง
โดยปกตินักพัฒนาซอฟต์แวร์มักจะสร้าง URI เนื้อหาจากผู้ออกใบรับรองโดยต่อท้ายเส้นทางที่ชี้ไปยัง
แต่ละตาราง เช่น หากคุณมี 2 ตาราง ได้แก่ table1 และ
table2 คุณสามารถรวมฟังก์ชันดังกล่าวกับผู้ออกใบรับรองจากตัวอย่างก่อนหน้านี้เพื่อแสดงผล
URI เนื้อหา
com.example.<appname>.provider/table1
และ
com.example.<appname>.provider/table2
เส้นทางไม่เท่ากับ
กลุ่มเดียวเท่านั้น และไม่จำเป็นต้องมีตารางสำหรับเส้นทางแต่ละระดับ
จัดการรหัส URI ของเนื้อหา
ตามหลักแล้ว ผู้ให้บริการจะเสนอการเข้าถึงแถวเดียวในตารางโดยการยอมรับ URI เนื้อหา
ด้วยค่ารหัสสำหรับแถวที่ท้าย URI นอกจากนี้ ตามปกติแล้ว ผู้ให้บริการจะจับคู่กับ
รหัสลงในคอลัมน์ _ID
ของตารางและดำเนินการเข้าถึงตามที่ขอกับ
แถวที่ตรงกัน
ข้อตกลงนี้จะเอื้อให้เกิดรูปแบบการออกแบบทั่วไปสำหรับแอปที่เข้าถึงผู้ให้บริการ แอป
จะค้นหากับผู้ให้บริการและแสดงผล Cursor
ใน ListView
โดยใช้ CursorAdapter
คำจำกัดความของ CursorAdapter
ต้องการคอลัมน์ใดคอลัมน์หนึ่งใน
Cursor
จะเป็น _ID
จากนั้นผู้ใช้จะเลือกแถวที่แสดงแถวใดแถวหนึ่งจาก UI เพื่อดูหรือแก้ไข
แอปจะได้รับแถวที่เกี่ยวข้องจาก Cursor
ที่สำรองข้อมูล
ListView
รับค่า_ID
สำหรับแถวนี้ นำไปต่อท้าย
URI เนื้อหา แล้วส่งคำขอเข้าถึงไปยังผู้ให้บริการ จากนั้นผู้ให้บริการจะดำเนินการ
ข้อความค้นหาหรือการแก้ไขตามแถวที่ผู้ใช้เลือกทุกประการ
รูปแบบ URI ของเนื้อหา
API ของผู้ให้บริการเพื่อช่วยคุณเลือกการดําเนินการสําหรับ URI เนื้อหาที่เข้ามาใหม่
คลาสช่วยอำนวยความสะดวก UriMatcher
ซึ่งแมปรูปแบบ URI เนื้อหากับ
ค่าจำนวนเต็ม คุณสามารถใช้ค่าจำนวนเต็มในคำสั่ง switch
ซึ่ง
เลือกการทำงานที่ต้องการสำหรับ URI เนื้อหาหรือ URI ที่ตรงกับรูปแบบที่เฉพาะเจาะจง
รูปแบบ URI เนื้อหาจะจับคู่ URI เนื้อหาโดยใช้อักขระไวลด์การ์ดดังนี้
-
*
จะจับคู่สตริงของอักขระที่ถูกต้องที่มีความยาวเท่าใดก็ได้ -
#
จะจับคู่สตริงของอักขระที่เป็นตัวเลขความยาวเท่าใดก็ได้
สำหรับตัวอย่างของการออกแบบและการเขียนโค้ดการจัดการ URI เนื้อหา ให้พิจารณาผู้ให้บริการที่มี
ผู้ออกใบรับรอง com.example.app.provider
ที่ยอมรับ URI เนื้อหาต่อไปนี้
ชี้ไปที่ตาราง:
-
content://com.example.app.provider/table1
: ตารางชื่อtable1
-
content://com.example.app.provider/table2/dataset1
: ตารางชื่อdataset1
-
content://com.example.app.provider/table2/dataset2
: ตารางชื่อdataset2
-
content://com.example.app.provider/table3
: ตารางชื่อtable3
ผู้ให้บริการยังรู้จัก URI เนื้อหาเหล่านี้หากมีรหัสแถวต่อท้ายด้วย เช่น content://com.example.app.provider/table3/1
สำหรับแถวที่ระบุโดย
1
ในtable3
รูปแบบ URI ของเนื้อหาที่เป็นไปได้มีดังนี้
-
content://com.example.app.provider/*
- จับคู่ URI เนื้อหาในผู้ให้บริการ
-
content://com.example.app.provider/table2/*
-
จับคู่ URI เนื้อหาสำหรับตาราง
dataset1
และdataset2
แต่ไม่ตรงกับ URI เนื้อหาสำหรับtable1
หรือtable3
-
content://com.example.app.provider/table3/#
-
ตรงกับ URI เนื้อหา
สำหรับแถวเดี่ยวใน
table3
เช่นcontent://com.example.app.provider/table3/6
สำหรับแถวที่ระบุโดย6
ข้อมูลโค้ดต่อไปนี้แสดงวิธีการทำงานของเมธอดใน UriMatcher
โค้ดนี้จะจัดการ URI สำหรับทั้งตารางแตกต่างจาก URI สำหรับ
แถวเดียวโดยใช้รูปแบบ URI ของเนื้อหา
content://<authority>/<path>
สำหรับตารางและ
content://<authority>/<path>/<id>
สำหรับแถวเดี่ยว
เมธอด addURI()
จะแมป
และพาธไปยังค่าจำนวนเต็ม เมธอด match()
จะแสดงผลค่าจำนวนเต็มสำหรับ URI ใบแจ้งยอดของ switch
เลือกได้ระหว่างการค้นหาทั้งตารางและการค้นหาสำหรับระเบียนเดียว
Kotlin
private val sUriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply { /* * The calls to addURI() go here for all the content URI patterns that the provider * recognizes. For this snippet, only the calls for table 3 are shown. */ /* * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used * in the path. */ addURI("com.example.app.provider", "table3", 1) /* * Sets the code for a single row to 2. In this case, the # wildcard is * used. content://com.example.app.provider/table3/3 matches, but * content://com.example.app.provider/table3 doesn't. */ addURI("com.example.app.provider", "table3/#", 2) } ... class ExampleProvider : ContentProvider() { ... // Implements ContentProvider.query() override fun query( uri: Uri?, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String? ): Cursor? { var localSortOrder: String = sortOrder ?: "" var localSelection: String = selection ?: "" when (sUriMatcher.match(uri)) { 1 -> { // If the incoming URI was for all of table3 if (localSortOrder.isEmpty()) { localSortOrder = "_ID ASC" } } 2 -> { // If the incoming URI was for a single row /* * Because this URI was for a single row, the _ID value part is * present. Get the last path segment from the URI; this is the _ID value. * Then, append the value to the WHERE clause for the query. */ localSelection += "_ID ${uri?.lastPathSegment}" } else -> { // If the URI isn't recognized, // do some error handling here } } // Call the code to actually do the query } }
Java
public class ExampleProvider extends ContentProvider { ... // Creates a UriMatcher object. private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); static { /* * The calls to addURI() go here for all the content URI patterns that the provider * recognizes. For this snippet, only the calls for table 3 are shown. */ /* * Sets the integer value for multiple rows in table 3 to one. No wildcard is used * in the path. */ uriMatcher.addURI("com.example.app.provider", "table3", 1); /* * Sets the code for a single row to 2. In this case, the # wildcard is * used. content://com.example.app.provider/table3/3 matches, but * content://com.example.app.provider/table3 doesn't. */ uriMatcher.addURI("com.example.app.provider", "table3/#", 2); } ... // Implements ContentProvider.query() public Cursor query( Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { ... /* * Choose the table to query and a sort order based on the code returned for the incoming * URI. Here, too, only the statements for table 3 are shown. */ switch (uriMatcher.match(uri)) { // If the incoming URI was for all of table3 case 1: if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC"; break; // If the incoming URI was for a single row case 2: /* * Because this URI was for a single row, the _ID value part is * present. Get the last path segment from the URI; this is the _ID value. * Then, append the value to the WHERE clause for the query. */ selection = selection + "_ID = " + uri.getLastPathSegment(); break; default: ... // If the URI isn't recognized, do some error handling here } // Call the code to actually do the query }
ContentUris
อีกชั้นเรียนหนึ่งมีวิธีการที่สะดวกในการทำงาน
ด้วยส่วน id
ของ URI เนื้อหา ชั้นเรียน Uri
และ
Uri.Builder
มีวิธีการอำนวยความสะดวกในการแยกวิเคราะห์
Uri
และสร้างออบเจ็กต์ใหม่
ใช้คลาส ContentProvider
อินสแตนซ์ ContentProvider
จัดการการเข้าถึง
ไปยังชุดข้อมูลที่มีโครงสร้างโดยจัดการคำขอจากแอปพลิเคชันอื่น แบบฟอร์มทั้งหมด
ของการเข้าถึงเรียกอีกชื่อหนึ่งว่า ContentResolver
ซึ่งทำให้เกิดเป็นรูปธรรมขึ้นมา
วิธี ContentProvider
เพื่อรับสิทธิ์เข้าถึง
วิธีการที่จำเป็น
คลาส Abstract ContentProvider
จะกำหนดเมธอด Abstract จำนวน 6 เมธอดที่
ที่คุณใช้เป็นส่วนหนึ่งของคลาสย่อยที่เป็นรูปธรรม วิธีการเหล่านี้ทั้งหมดยกเว้น
แอปพลิเคชันไคลเอ็นต์จะเรียกใช้ onCreate()
ที่พยายามเข้าถึงผู้ให้บริการเนื้อหาของคุณ
-
query()
-
เรียกดูข้อมูลจากผู้ให้บริการ ใช้อาร์กิวเมนต์เพื่อเลือกตาราง
แถวและคอลัมน์ที่จะแสดงผล รวมถึงลำดับการจัดเรียงของผลลัพธ์
แสดงผลข้อมูลเป็นออบเจ็กต์
Cursor
-
insert()
- แทรกแถวใหม่ลงในผู้ให้บริการ ใช้อาร์กิวเมนต์เพื่อเลือก ปลายทาง และรับค่าคอลัมน์ที่จะใช้ แสดงผล URI เนื้อหาสำหรับ แถวที่แทรกใหม่
-
update()
- อัปเดตแถวที่มีอยู่ในผู้ให้บริการ ใช้อาร์กิวเมนต์เพื่อเลือกตารางและแถว เพื่ออัปเดตและรับค่าของคอลัมน์ที่อัปเดต แสดงผลจำนวนแถวที่อัปเดต
-
delete()
- ลบแถวจากผู้ให้บริการ ใช้อาร์กิวเมนต์เพื่อเลือกตารางและแถวที่จะ ลบ แสดงผลจำนวนแถวที่ลบ
-
getType()
- แสดงผลประเภท MIME ที่สอดคล้องกับ URI เนื้อหา มีคำอธิบายวิธีการนี้ในหัวข้อ รายละเอียดในส่วนใช้งานประเภท MIME ของผู้ให้บริการเนื้อหา
-
onCreate()
-
เริ่มต้นผู้ให้บริการ ระบบ Android เรียกใช้วิธีการนี้ทันทีหลังจาก
จะสร้างผู้ให้บริการ ระบบจะไม่สร้างผู้ให้บริการจนกว่า
ออบเจ็กต์
ContentResolver
รายการพยายามเข้าถึง
เมธอดเหล่านี้มีลายเซ็นเหมือนกับชื่อที่มีชื่อเดียวกัน
ContentResolver
วิธี
การใช้วิธีการเหล่านี้จะต้องคำนึงถึงสิ่งต่อไปนี้
-
ทุกวิธียกเว้น
onCreate()
สามารถเรียกใช้โดยชุดข้อความหลายรายการพร้อมกันได้ ชุดข้อความเหล่านั้นจึงปลอดภัยต่อชุดข้อความ เพื่อเรียนรู้ ข้อมูลเพิ่มเติมเกี่ยวกับชุดข้อความต่างๆ โปรดดู ภาพรวมกระบวนการและชุดข้อความ -
หลีกเลี่ยงการดำเนินการที่ใช้เวลานานใน
onCreate()
เลื่อนงานเริ่มต้นจนกว่าจะจำเป็นจริงๆ หัวข้อเกี่ยวกับการใช้เมธอด onCreate() พูดถึงเรื่องนี้โดยละเอียดยิ่งขึ้น -
ถึงแม้ว่าคุณจะต้องปรับใช้วิธีการเหล่านี้ แต่โค้ดของคุณไม่จำเป็นต้องดำเนินการใดๆ ยกเว้น
แสดงผลประเภทข้อมูลที่ต้องการ เช่น คุณสามารถป้องกันไม่ให้แอปพลิเคชันอื่นๆ
ไม่ให้แทรกข้อมูลลงในบางตารางโดยการไม่สนใจการเรียกใช้ไปยัง
insert()
และการกลับ 0.
ใช้เมธอด query()
เมธอด ContentProvider.query()
ต้องแสดงผลออบเจ็กต์ Cursor
หรือถ้า
ล้มเหลว แสดงผล Exception
หากใช้ฐานข้อมูล SQLite เป็นข้อมูลของคุณ
คุณสามารถส่งคืน Cursor
ที่แสดงผลโดยหนึ่งใน
query()
เมธอดของคลาส SQLiteDatabase
หากคำค้นหาไม่ตรงกับแถวใดเลย ให้แสดงผล Cursor
อินสแตนซ์ที่เมธอด getCount()
แสดงผลเป็น 0
แสดงผล null
ต่อเมื่อเกิดข้อผิดพลาดภายในระหว่างขั้นตอนการค้นหา
หากคุณไม่ได้ใช้ฐานข้อมูล SQLite เป็นพื้นที่เก็บข้อมูล ให้ใช้คลาสย่อยที่เป็นรูปธรรมรายการใดรายการหนึ่ง
จาก Cursor
เช่น คลาส MatrixCursor
ใช้เคอร์เซอร์ซึ่งแต่ละแถวคืออาร์เรย์ของ Object
อินสแตนซ์ ในชั้นเรียนนี้
ใช้ addRow()
เพื่อเพิ่มแถวใหม่
ระบบ Android ต้องสามารถสื่อสารกับ Exception
ข้ามขอบเขตของกระบวนการ Android สามารถดำเนินการนี้ได้สำหรับข้อยกเว้นที่เป็นประโยชน์ต่อไปนี้
ในการจัดการกับข้อผิดพลาดในการค้นหา:
-
IllegalArgumentException
คุณสามารถเลือกข้ามตัวเลือกนี้ได้ในกรณีที่ผู้ให้บริการ ได้รับ URI เนื้อหาที่ไม่ถูกต้อง -
NullPointerException
ใช้เมธอด Insert()
เมธอด insert()
จะเพิ่ม
แถวใหม่ไปยังตารางที่เหมาะสมโดยใช้ค่าใน ContentValues
อาร์กิวเมนต์ หากไม่มีชื่อคอลัมน์ในอาร์กิวเมนต์ ContentValues
คุณจะ
คุณอาจต้องระบุค่าเริ่มต้นในรหัสผู้ให้บริการหรือในฐานข้อมูล
สคีมา
วิธีนี้จะแสดง URI เนื้อหาสำหรับแถวใหม่ ในการสร้าง URL นี้ ให้เพิ่มพารามิเตอร์
คีย์หลักของแถว โดยปกติแล้วจะเป็นค่า _ID
ไปยัง URI เนื้อหาของตาราง โดยใช้
withAppendedId()
ใช้เมธอด delete()
เมธอด delete()
จะไม่จำเป็นต้องลบแถวออกจากพื้นที่เก็บข้อมูล หากใช้อะแดปเตอร์การซิงค์
กับผู้ให้บริการของคุณ ลองทำเครื่องหมายแถวที่ถูกลบ
ด้วยการ "ลบ" แทนการลบทั้งแถวออก อะแดปเตอร์การซิงค์
ตรวจหาแถวที่ถูกลบ และนำออกจากเซิร์ฟเวอร์ก่อนที่จะลบจากผู้ให้บริการ
ใช้เมธอด update()
เมธอด update()
ใช้อาร์กิวเมนต์ ContentValues
เดียวกันกับที่ใช้โดย
insert()
และ
ใช้ selection
และ selectionArgs
อาร์กิวเมนต์เดียวกัน
delete()
และ
ContentProvider.query()
ซึ่งอาจทำให้คุณนำโค้ดมาใช้ซ้ำระหว่างวิธีการเหล่านี้ได้
ใช้เมธอด onCreate()
ระบบ Android เรียก onCreate()
เมื่อผู้ให้บริการเริ่มทำงาน ดำเนินการเริ่มต้นแบบรวดเร็วเท่านั้น
งานในเมธอดนี้และจะเลื่อนการสร้างฐานข้อมูลและการโหลดข้อมูลจนกว่าผู้ให้บริการ
ได้รับคำขอข้อมูล ถ้าคุณทำงานยาวๆ
onCreate()
คุณลดความเร็ว
ผู้ให้บริการใหม่ ซึ่งจะทำให้การตอบกลับจากผู้ให้บริการช้าลง
แอปพลิเคชัน
ข้อมูลโค้ดสองชุดต่อไปนี้แสดงการโต้ตอบระหว่าง
ContentProvider.onCreate()
และ
Room.databaseBuilder()
องค์ประกอบ
ข้อมูลโค้ดแสดงการใช้งาน
ContentProvider.onCreate()
โดยที่
มีการสร้างออบเจ็กต์ฐานข้อมูลและแฮนเดิลให้กับออบเจ็กต์การเข้าถึงข้อมูลแล้ว
Kotlin
// Defines the database name private const val DBNAME = "mydb" ... class ExampleProvider : ContentProvider() { // Defines a handle to the Room database private lateinit var appDatabase: AppDatabase // Defines a Data Access Object to perform the database operations private var userDao: UserDao? = null override fun onCreate(): Boolean { // Creates a new database object appDatabase = Room.databaseBuilder(context, AppDatabase::class.java, DBNAME).build() // Gets a Data Access Object to perform the database operations userDao = appDatabase.userDao return true } ... // Implements the provider's insert method override fun insert(uri: Uri, values: ContentValues?): Uri? { // Insert code here to determine which DAO to use when inserting data, handle error conditions, etc. } }
Java
public class ExampleProvider extends ContentProvider // Defines a handle to the Room database private AppDatabase appDatabase; // Defines a Data Access Object to perform the database operations private UserDao userDao; // Defines the database name private static final String DBNAME = "mydb"; public boolean onCreate() { // Creates a new database object appDatabase = Room.databaseBuilder(getContext(), AppDatabase.class, DBNAME).build(); // Gets a Data Access Object to perform the database operations userDao = appDatabase.getUserDao(); return true; } ... // Implements the provider's insert method public Cursor insert(Uri uri, ContentValues values) { // Insert code here to determine which DAO to use when inserting data, handle error conditions, etc. } }
การใช้งานประเภท MIME ของ ContentProvider
คลาส ContentProvider
มี 2 วิธีในการส่งคืนประเภท MIME ดังนี้
-
getType()
- หนึ่งในวิธีการที่จำเป็นซึ่งคุณนำไปใช้กับผู้ให้บริการรายใดก็ได้
-
getStreamTypes()
- วิธีการที่คุณควรใช้หากผู้ให้บริการของคุณมีไฟล์
ประเภท MIME สำหรับตาราง
เมธอด getType()
แสดงผล
String
ในรูปแบบ MIME ที่อธิบายประเภทข้อมูลที่เนื้อหาแสดงผล
อาร์กิวเมนต์ URI อาร์กิวเมนต์ Uri
อาจเป็นรูปแบบ ไม่ใช่ URI ที่เจาะจง
ในกรณีนี้ ให้แสดงผลประเภทข้อมูลที่เชื่อมโยงกับ URI เนื้อหาที่ตรงกับ
รูปแบบ
สำหรับข้อมูลประเภททั่วไป เช่น ข้อความ, HTML หรือ JPEG
getType()
แสดงค่ามาตรฐาน
ประเภท MIME สำหรับข้อมูลนั้น คุณสามารถดูรายการประเภทมาตรฐานเหล่านี้ได้ที่
ประเภทสื่อ MIME ของ IANA
เว็บไซต์ของคุณ
สำหรับ URI เนื้อหาที่ชี้ไปยังแถวหรือแถวของข้อมูลในตาราง
getType()
ทำรีเทิร์น
ประเภท MIME ในรูปแบบ MIME เฉพาะผู้ให้บริการของ Android ได้แก่
-
ประเภทส่วน:
vnd
-
ส่วนประเภทย่อย:
-
หากรูปแบบ URI มีไว้สำหรับแถวเดียว:
android.cursor.item/
-
หากรูปแบบ URI มีไว้สำหรับแถวมากกว่า 1 แถว:
android.cursor.dir/
-
หากรูปแบบ URI มีไว้สำหรับแถวเดียว:
-
ส่วนเฉพาะผู้ให้บริการ:
vnd.<name>
<type>
คุณระบุ
<name>
และ<type>
ค่า<name>
ไม่ซ้ำกันทั่วโลก และค่า<type>
จะเป็นค่าเฉพาะสำหรับ URI ที่เกี่ยวข้อง รูปแบบ ตัวเลือกที่ดีสำหรับ<name>
คือชื่อบริษัทของคุณหรือ บางส่วนของชื่อแพ็กเกจ Android ของแอปพลิเคชันของคุณ ตัวเลือกที่ดีสำหรับ<type>
คือสตริงที่ระบุตารางที่เชื่อมโยงกับ URI
ตัวอย่างเช่น หากสิทธิ์ของผู้ให้บริการคือ
com.example.app.provider
และแสดงตารางที่ชื่อ
table1
ประเภท MIME สำหรับหลายแถวใน table1
คือ
vnd.android.cursor.dir/vnd.com.example.provider.table1
สำหรับ table1
แถวเดียว ประเภท MIME จะเป็น
vnd.android.cursor.item/vnd.com.example.provider.table1
ประเภท MIME สำหรับไฟล์
หากผู้ให้บริการของคุณมีไฟล์ ให้ใช้
getStreamTypes()
เมธอดจะแสดงอาร์เรย์ String
ของประเภท MIME สำหรับไฟล์ของผู้ให้บริการ
สามารถแสดงผลสำหรับ URI เนื้อหาที่ระบุ กรองประเภท MIME ที่คุณเสนอตามประเภท MIME
กรองเพื่อให้แสดงผลเฉพาะประเภท MIME ที่ไคลเอ็นต์ต้องการจัดการ
เช่น ลองพิจารณาผู้ให้บริการที่เสนอรูปภาพเป็นไฟล์รูปแบบ JPG
PNG และ GIF
หากแอปพลิเคชันเรียกใช้ ContentResolver.getStreamTypes()
ด้วยสตริงตัวกรอง image/*
สำหรับบางสิ่งที่
เป็น "รูปภาพ"
เมธอด ContentProvider.getStreamTypes()
จะแสดงอาร์เรย์
{ "image/jpeg", "image/png", "image/gif"}
หากแอปสนใจเฉพาะไฟล์ JPG ก็สามารถเรียก
ContentResolver.getStreamTypes()
โดยใช้สตริงตัวกรอง *\/jpeg
และ
getStreamTypes()
ส่งกลับ:
{"image/jpeg"}
หากผู้ให้บริการไม่มีประเภท MIME ที่ขอในสตริงตัวกรอง
getStreamTypes()
แสดงผล null
ใช้คลาส Contract
คลาสสัญญาเป็นคลาส public final
ที่มีคำจำกัดความคงที่สำหรับ
URI, ชื่อคอลัมน์, ประเภท MIME และข้อมูลเมตาอื่นๆ ที่เกี่ยวข้องกับผู้ให้บริการ ชั้นเรียน
ทำสัญญาระหว่างผู้ให้บริการกับแอปพลิเคชันอื่นๆ โดยตรวจสอบว่าผู้ให้บริการ
สามารถเข้าถึงได้อย่างถูกต้อง แม้ว่าจะมีการเปลี่ยนแปลงค่าจริงของ URI, ชื่อคอลัมน์
เป็นต้น
คลาสสัญญายังช่วยนักพัฒนาซอฟต์แวร์เพราะมักจะมีชื่อช่วยจำสำหรับค่าคงที่ ดังนั้น นักพัฒนาซอฟต์แวร์จึงมีโอกาสน้อยลงที่จะใช้ค่าที่ไม่ถูกต้องสำหรับชื่อคอลัมน์หรือ URI เนื่องจากเป็น สามารถมีเอกสาร Javadoc ได้ สภาพแวดล้อมในการพัฒนาซอฟต์แวร์แบบผสานรวม เช่น Android Studio สามารถเติมชื่อคงที่โดยอัตโนมัติจากคลาสสัญญาและแสดง Javadoc สำหรับ ค่าคงที่นี้
นักพัฒนาแอปจะไม่สามารถเข้าถึงไฟล์ชั้นเรียนของคลาสสัญญาจากแอปพลิเคชันของคุณ แต่สามารถ ทำการคอมไพล์ลงในแอปพลิเคชันโดยใช้ไฟล์ JAR ที่คุณมี
คลาส ContactsContract
และคลาสที่ซ้อนกันเป็นตัวอย่างของ
คลาสที่มีสัญญาสูง
ใช้สิทธิ์ของผู้ให้บริการเนื้อหา
สิทธิ์และการเข้าถึงระบบ Android ในทุกด้านมีอธิบายไว้อย่างละเอียดใน เคล็ดลับความปลอดภัย ภาพรวมของพื้นที่เก็บข้อมูลและไฟล์ยัง อธิบายความปลอดภัยและสิทธิ์ที่จะมีผลสำหรับพื้นที่เก็บข้อมูลประเภทต่างๆ กล่าวโดยสรุปคือประเด็นสำคัญมีดังต่อไปนี้
- โดยค่าเริ่มต้น ไฟล์ข้อมูลที่จัดเก็บในที่จัดเก็บข้อมูลภายในของอุปกรณ์จะเป็นแบบส่วนตัว แอปพลิเคชันและผู้ให้บริการ
-
ฐานข้อมูล
SQLiteDatabase
รายการที่คุณสร้างจะเป็นแบบส่วนตัว แอปพลิเคชันและผู้ให้บริการ - โดยค่าเริ่มต้น ไฟล์ข้อมูลที่คุณบันทึกลงในพื้นที่เก็บข้อมูลภายนอกจะเป็นสาธารณะและ ที่อ่านได้ทั่วโลก คุณใช้ผู้ให้บริการเนื้อหาเพื่อจำกัดการเข้าถึงไฟล์ใน ที่จัดเก็บข้อมูลภายนอก เนื่องจากแอปพลิเคชันอื่นสามารถใช้การเรียก API อื่นๆ เพื่ออ่านและเขียนได้
- เมธอดนี้จะเรียกร้องให้เปิดหรือสร้างไฟล์หรือฐานข้อมูล SQLite ภายในอุปกรณ์ พื้นที่เก็บข้อมูลอาจให้สิทธิ์ทั้งการอ่านและเขียนแอปพลิเคชันอื่นๆ ทั้งหมด หากคุณ ใช้ไฟล์หรือฐานข้อมูลภายในเป็นที่เก็บของผู้ให้บริการ และให้ "สามารถอ่านได้ทั่วโลก" หรือ "world-writeable" สิทธิ์ที่คุณกำหนดไว้สำหรับผู้ให้บริการ ไฟล์ Manifest ของไฟล์ดังกล่าวไม่ปกป้องข้อมูลของคุณ การเข้าถึงเริ่มต้นสำหรับไฟล์และฐานข้อมูลใน ที่จัดเก็บข้อมูลภายในเป็นแบบ "ส่วนตัว" ไม่ต้องเปลี่ยนการตั้งค่านี้สำหรับที่เก็บของผู้ให้บริการ
หากต้องการใช้สิทธิ์ของผู้ให้บริการเนื้อหาเพื่อควบคุมการเข้าถึงข้อมูลของคุณ ให้ทำดังนี้ จัดเก็บข้อมูลของคุณในไฟล์ภายใน ฐานข้อมูล SQLite หรือระบบคลาวด์ เช่น บนเซิร์ฟเวอร์ระยะไกล และเก็บไฟล์และฐานข้อมูลเป็นส่วนตัวในแอปพลิเคชันของคุณ
ใช้สิทธิ์
โดยค่าเริ่มต้น แอปพลิเคชันทั้งหมดจะอ่านหรือเขียนข้อมูลจากผู้ให้บริการได้ แม้ว่าข้อมูลสำคัญจะเป็น
เป็นส่วนตัว เนื่องจากโดยค่าเริ่มต้นผู้ให้บริการของคุณไม่ได้ตั้งค่าสิทธิ์ไว้ หากต้องการเปลี่ยนแปลง
ตั้งค่าสิทธิ์สำหรับผู้ให้บริการในไฟล์ Manifest โดยใช้แอตทริบิวต์หรือหน่วยย่อย
ขององค์ประกอบ
<provider>
คุณสามารถตั้งค่าสิทธิ์ที่ใช้กับผู้ให้บริการทั้งหมด
กับบางตาราง บางบันทึก หรือทั้งสามรายการ
คุณกำหนดสิทธิ์สำหรับผู้ให้บริการ
องค์ประกอบ
<permission>
ในไฟล์ Manifest หากต้องการทำให้
ของผู้ให้บริการของคุณโดยเฉพาะ ให้ใช้การกำหนดขอบเขตแบบ Java สำหรับ
android:name
เช่น ตั้งชื่อสิทธิ์อ่าน
com.example.app.provider.permission.READ_PROVIDER
รายการต่อไปนี้จะอธิบายขอบเขตสิทธิ์ของผู้ให้บริการ โดยเริ่มจาก ที่ใช้กับผู้ให้บริการทั้งหมด และทำให้มีความละเอียดมากขึ้น สิทธิ์ที่มีความละเอียดมากกว่าจะมีลำดับความสำคัญสูงกว่าสิทธิ์ที่มีขอบเขตใหญ่กว่า
- สิทธิ์ระดับผู้ให้บริการแบบอ่านและเขียนรายการเดียว
-
สิทธิ์ 1 รายการที่ควบคุมทั้งสิทธิ์อ่านและเขียนสำหรับผู้ให้บริการทั้งหมด ระบุ
ที่มีแอตทริบิวต์
android:permission
ของค่า องค์ประกอบ<provider>
- แยกสิทธิ์ระดับผู้ให้บริการในการอ่านและเขียน
-
สิทธิ์อ่านและสิทธิ์ในการเขียนสำหรับผู้ให้บริการทั้งหมด คุณเป็นคนระบุ
ด้วย
android:readPermission
และandroid:writePermission
ของแอตทริบิวต์ องค์ประกอบ<provider>
โดยจะมีลำดับความสำคัญเหนือกว่าสิทธิ์ที่กำหนดโดยandroid:permission
- สิทธิ์ระดับเส้นทาง
-
สิทธิ์อ่าน เขียน หรืออ่าน/เขียนสำหรับ URI เนื้อหาในผู้ให้บริการ คุณระบุ
URI แต่ละรายการที่คุณต้องการควบคุมด้วย
<path-permission>
องค์ประกอบย่อยของ องค์ประกอบ<provider>
สำหรับ URI เนื้อหาแต่ละรายการที่คุณระบุ คุณสามารถระบุ สิทธิ์อ่าน/เขียน สิทธิ์อ่าน สิทธิ์เขียน หรือทั้ง 3 อย่าง การอ่านและ สิทธิ์การเขียนจะมีผลเหนือกว่าสิทธิ์อ่าน/เขียน รวมถึงที่ระดับเส้นทาง จะมีความสำคัญเหนือสิทธิ์ระดับผู้ให้บริการ - สิทธิ์ชั่วคราว
-
ระดับสิทธิ์ที่ให้สิทธิ์เข้าถึงแอปพลิเคชันชั่วคราว แม้ว่าแอปพลิเคชันนั้น
ไม่มีสิทธิ์ที่จำเป็นตามปกติ รูปภาพชั่วคราว
ฟีเจอร์การเข้าถึงช่วยลดจำนวนสิทธิ์ที่แอปพลิเคชันต้องขอ
ไฟล์ Manifest เมื่อคุณเปิดสิทธิ์ชั่วคราว แอปพลิเคชันเดียวที่จำเป็นต้องใช้
สิทธิ์ถาวรสำหรับผู้ให้บริการของคุณคือรายการที่เข้าถึง
ข้อมูลของคุณ
ตัวอย่างเช่น พิจารณาสิทธิ์ที่คุณต้องมีหากติดตั้งใช้งานผู้ให้บริการอีเมลและแอป และคุณ ต้องการให้แอปพลิเคชันโปรแกรมดูรูปภาพภายนอกแสดงไฟล์แนบที่เป็นรูปภาพจาก หากต้องการให้สิทธิ์เข้าถึงที่จำเป็นแก่โปรแกรมดูรูปภาพโดยไม่ต้องขอสิทธิ์ ให้ทำดังนี้ คุณสามารถตั้งค่าสิทธิ์ชั่วคราวสำหรับ URI เนื้อหาสำหรับรูปภาพ
ออกแบบแอปอีเมลเพื่อ เมื่อผู้ใช้ต้องการแสดงรูปภาพ แอปจะส่ง Intent ที่มี URI เนื้อหาของรูปภาพและธงสิทธิ์ให้กับโปรแกรมดูรูปภาพ โปรแกรมดูรูปภาพสามารถ ให้ค้นหาผู้ให้บริการอีเมลของคุณเพื่อเรียกรูปภาพ แม้ว่าผู้ดูจะไม่ มีสิทธิ์อ่านตามปกติสำหรับผู้ให้บริการ
หากต้องการเปิดสิทธิ์ชั่วคราว ให้ตั้งค่า แอตทริบิวต์
android:grantUriPermissions
ของ<provider>
องค์ประกอบหรือเพิ่มอย่างน้อย 1 รายการ<grant-uri-permission>
องค์ประกอบย่อยลงใน องค์ประกอบ<provider>
โทรContext.revokeUriPermission()
เมื่อใดก็ตามที่คุณเลิกรองรับ URI เนื้อหาที่เชื่อมโยงกับสิทธิ์ชั่วคราวจากค่าของแอตทริบิวต์จะกำหนดจำนวนผู้ให้บริการที่สามารถเข้าถึงได้ หากตั้งค่าแอตทริบิวต์เป็น
"true"
ระบบจะให้สิทธิ์ชั่วคราว สิทธิ์สำหรับผู้ให้บริการทั้งหมด โดยลบล้างสิทธิ์อื่นๆ ที่จำเป็น ตามสิทธิ์ระดับผู้ให้บริการหรือระดับเส้นทางหากตั้งค่าสถานะนี้เป็น
"false"
ให้เพิ่ม<grant-uri-permission>
องค์ประกอบย่อยลงใน องค์ประกอบ<provider>
องค์ประกอบย่อยแต่ละรายการจะระบุ URI เนื้อหาหรือ URI ที่ได้รับสิทธิ์เข้าถึงชั่วคราวหากต้องการมอบสิทธิ์เข้าถึงชั่วคราวไปยังแอปพลิเคชัน Intent นั้นต้องมี ธง
FLAG_GRANT_READ_URI_PERMISSION
แฟล็กFLAG_GRANT_WRITE_URI_PERMISSION
หรือทั้งคู่ เหล่านี้ ได้รับการตั้งค่าด้วยเมธอดsetFlags()
หากไม่มีแอตทริบิวต์
android:grantUriPermissions
ระบบจะถือว่าเป็น"false"
<provider> องค์ประกอบ
เช่น คอมโพเนนต์ Activity
และ Service
คลาสย่อยของ ContentProvider
ในไฟล์ Manifest ของแอปพลิเคชันนั้น โดยใช้
องค์ประกอบ
<provider>
ระบบ Android ได้รับข้อมูลต่อไปนี้จาก
องค์ประกอบ
-
หน่วยงาน
(
android:authorities
) - ชื่อสัญลักษณ์ที่ระบุผู้ให้บริการทั้งหมดภายในระบบ ช่วงเวลานี้ ได้รับการอธิบายโดยละเอียดยิ่งขึ้นใน ออกแบบ URI เนื้อหา
-
ชื่อคลาสของผู้ให้บริการ
(
android:name
) -
คลาสที่ใช้
ContentProvider
ชั้นเรียนนี้ ซึ่งอธิบายโดยละเอียดยิ่งขึ้นใน ใช้คลาส ContentProvider - สิทธิ์
-
แอตทริบิวต์ที่ระบุสิทธิ์ที่แอปพลิเคชันอื่นต้องมีเพื่อเข้าถึง
ข้อมูลของผู้ให้บริการ
-
android:grantUriPermissions
: แฟล็กสิทธิ์ชั่วคราว -
android:permission
: สิทธิ์อ่าน/เขียนทั่วทั้งผู้ให้บริการรายเดียว -
android:readPermission
: สิทธิ์อ่านทั่วทั้งผู้ให้บริการ -
android:writePermission
: สิทธิ์เขียนทั่วทั้งผู้ให้บริการ
สิทธิ์และแอตทริบิวต์ที่เกี่ยวข้องมีการอธิบายไว้ในบทความเพิ่มเติม รายละเอียดใน ส่วนใช้สิทธิ์ของผู้ให้บริการเนื้อหา
-
- แอตทริบิวต์การเริ่มต้นและการควบคุม
-
แอตทริบิวต์เหล่านี้จะกำหนดวิธีการและเวลาที่ระบบ Android จะเริ่มต้นผู้ให้บริการ
ลักษณะกระบวนการของผู้ให้บริการและการตั้งค่ารันไทม์อื่นๆ
-
android:enabled
: ธงให้ระบบเริ่มต้นผู้ให้บริการ -
android:exported
: แจ้งการอนุญาตให้แอปพลิเคชันอื่นใช้ผู้ให้บริการรายนี้ -
android:initOrder
: ลำดับการเริ่มต้นผู้ให้บริการนี้ เมื่อเทียบกับผู้ให้บริการรายอื่นในกระบวนการเดียวกัน -
android:multiProcess
: ธงให้ระบบเริ่มต้นผู้ให้บริการ ในกระบวนการเดียวกับไคลเอ็นต์ที่โทร -
android:process
: ชื่อของกระบวนการที่ผู้ให้บริการเรียกใช้ -
android:syncable
: ธงที่ระบุว่าข้อมูลของผู้ให้บริการจะเป็น ซิงค์กับข้อมูลบนเซิร์ฟเวอร์
แอตทริบิวต์เหล่านี้ได้รับการระบุไว้อย่างชัดเจนในคู่มือ องค์ประกอบ
<provider>
-
- แอตทริบิวต์ที่ให้ข้อมูล
-
ไอคอนและป้ายกำกับที่ไม่บังคับสำหรับผู้ให้บริการ:
-
android:icon
: ทรัพยากรที่ถอนออกได้ที่มีไอคอนสำหรับผู้ให้บริการ ไอคอนนี้จะปรากฏถัดจากป้ายกำกับของผู้ให้บริการในรายการแอปใน การตั้งค่า > แอป > ทั้งหมด -
android:label
: ป้ายกำกับที่ให้ข้อมูลที่อธิบายผู้ให้บริการ ข้อมูล หรือทั้งสองอย่าง ป้ายกำกับจะปรากฏในรายการแอปใน การตั้งค่า > แอป > ทั้งหมด
แอตทริบิวต์เหล่านี้ได้รับการระบุไว้อย่างชัดเจนในคู่มือ องค์ประกอบ
<provider>
-
หมายเหตุ: หากคุณกําหนดเป้าหมายเป็น Android 11 ขึ้นไป โปรดดูที่ เอกสารประกอบเกี่ยวกับระดับการเข้าถึงแพ็กเกจ สำหรับการกำหนดค่าเพิ่มเติม
Intent และการเข้าถึงข้อมูล
แอปพลิเคชันสามารถเข้าถึงผู้ให้บริการเนื้อหาโดยอ้อมด้วย Intent
แอปพลิเคชันไม่ได้เรียกใช้เมธอดใดๆ ของ ContentResolver
หรือ
ContentProvider
แต่จะส่ง Intent ที่เริ่มกิจกรรม
ซึ่งมักเป็นส่วนหนึ่งของแอปพลิเคชันของผู้ให้บริการเอง กิจกรรมปลายทางรับผิดชอบ
ดึงข้อมูลและแสดงข้อมูลใน UI
ขึ้นอยู่กับการดำเนินการใน Intent กิจกรรมปลายทางยังแจ้งเตือนให้ผู้ใช้แก้ไขข้อมูลของผู้ให้บริการด้วย Intent อาจมีคำว่า "พิเศษ" อยู่ด้วย ข้อมูลที่กิจกรรมปลายทางแสดง ใน UI ผู้ใช้จะมีตัวเลือกในการเปลี่ยนแปลงข้อมูลนี้ก่อนที่จะนำไปใช้เพื่อปรับเปลี่ยน ในผู้ให้บริการ
คุณใช้การเข้าถึง Intent เพื่อช่วยความสมบูรณ์ของข้อมูลได้ ผู้ให้บริการของคุณอาจพึ่งพา เกี่ยวกับการแทรก อัปเดต และลบข้อมูลตามตรรกะทางธุรกิจที่กำหนดไว้อย่างเคร่งครัด ถ้า ในกรณีนี้ การปล่อยให้แอปพลิเคชันอื่นๆ แก้ไขข้อมูลของคุณได้โดยตรงอาจทำให้เกิด ข้อมูลไม่ถูกต้อง
หากต้องการให้นักพัฒนาซอฟต์แวร์ใช้การเข้าถึง Intent ให้จัดทำเอกสารอย่างละเอียด อธิบายว่าทำไมการเข้าถึงด้วยความตั้งใจโดยใช้ UI ของแอปพลิเคชันจึงดีกว่าการพยายาม แก้ไขข้อมูลด้วยโค้ด
การจัดการกับความตั้งใจที่เข้ามาใหม่ซึ่งต้องการปรับเปลี่ยนข้อมูลของผู้ให้บริการก็ไม่แตกต่างจาก การจัดการกับ Intent อื่นๆ คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับการใช้ Intent ด้วยการอ่าน ตัวกรอง Intent และ Intent
ดูข้อมูลที่เกี่ยวข้องเพิ่มเติมได้ที่ ภาพรวมผู้ให้บริการปฏิทิน